]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #73418 - doctorn:variants-intrinsic, r=kennytm
authorManish Goregaokar <manishsmail@gmail.com>
Fri, 26 Jun 2020 01:00:07 +0000 (18:00 -0700)
committerGitHub <noreply@github.com>
Fri, 26 Jun 2020 01:00:07 +0000 (18:00 -0700)
Add unstable `core::mem::variant_count` intrinsic

Adds a new `const fn` intrinsic which can be used to determine the number of variants in an `enum`.

I've shown this to a couple of people and they invariably ask 'why on earth?', but there's actually a very neat use case:

At the moment, if you want to create an opaque array type that's indexed by an `enum` with one element for each variant, you either have to hard-code the number of variants, add a `LENGTH` variant or use a `Vec`, none of which are suitable in general (number of variants could change; pattern matching `LENGTH` becomes frustrating; might not have `alloc`). By including this intrinsic, it becomes possible to write the following:

```rust
#[derive(Copy, Clone)]
enum OpaqueIndex {
    A = 0,
    B,
    C,
}

struct OpaqueVec<T>(Box<[T; std::mem::num_variants::<OpaqueIndex>()]>);

impl<T> std::ops::Index<OpaqueIndex> for OpaqueVec<T> {
    type Output = T;

    fn index(&self, idx: OpaqueIndex) -> &Self::Output {
        &self.0[idx as usize]
    }
}
```

(We even have a use cases for this in `rustc` and I plan to use it to re-implement the lang-items table.)

214 files changed:
Cargo.lock
src/doc/book
src/doc/embedded-book
src/doc/reference
src/doc/rust-by-example
src/liballoc/boxed.rs
src/liballoc/collections/btree/map.rs
src/liballoc/collections/vec_deque/tests.rs
src/liballoc/vec.rs
src/libcore/convert/num.rs
src/libcore/intrinsics.rs
src/libcore/ops/function.rs
src/libcore/tests/nonzero.rs
src/libpanic_abort/lib.rs
src/libpanic_unwind/lib.rs
src/librustc_ast_lowering/item.rs
src/librustc_ast_lowering/lib.rs
src/librustc_ast_pretty/pprust/tests.rs
src/librustc_codegen_llvm/back/write.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_ssa/back/link.rs
src/librustc_codegen_ssa/back/linker.rs
src/librustc_data_structures/sync.rs
src/librustc_driver/lib.rs
src/librustc_expand/mbe/macro_parser.rs
src/librustc_hir/definitions.rs
src/librustc_hir/hir.rs
src/librustc_hir/lang_items.rs
src/librustc_infer/infer/error_reporting/mod.rs
src/librustc_interface/interface.rs
src/librustc_interface/passes.rs
src/librustc_interface/queries.rs
src/librustc_lint/Cargo.toml
src/librustc_lint/lib.rs
src/librustc_lint/non_ascii_idents.rs
src/librustc_lint/types.rs
src/librustc_llvm/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/locator.rs
src/librustc_middle/hir/map/mod.rs
src/librustc_middle/ich/hcx.rs
src/librustc_middle/mir/mod.rs
src/librustc_middle/query/mod.rs
src/librustc_middle/ty/context.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/instrument_coverage.rs
src/librustc_mir/transform/mod.rs
src/librustc_parse/parser/mod.rs
src/librustc_passes/check_attr.rs
src/librustc_passes/lang_items.rs
src/librustc_resolve/Cargo.toml
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/check_unused.rs
src/librustc_resolve/def_collector.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/imports.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_session/config.rs
src/librustc_session/filesearch.rs
src/librustc_session/options.rs
src/librustc_session/parse.rs
src/librustc_span/symbol.rs
src/librustc_target/spec/apple_sdk_base.rs
src/librustc_trait_selection/traits/project.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/html/static/main.js
src/libstd/keyword_docs.rs
src/libstd/os/illumos/fs.rs
src/libstd/panicking.rs
src/libstd/rt.rs
src/libstd/sys/sgx/abi/mod.rs
src/libstd/sys/unix/ext/net.rs
src/libstd/sys/vxworks/args.rs
src/libstd/sys/vxworks/ext/fs.rs
src/libstd/sys/vxworks/rand.rs
src/libstd/sys/vxworks/rwlock.rs
src/libstd/sys/vxworks/time.rs
src/libstd/sys/wasi/alloc.rs
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop_miscompile.rs [new file with mode: 0644]
src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff [new file with mode: 0644]
src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter-out.js [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter-out.rs [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter.js [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter.rs [new file with mode: 0644]
src/test/rustdoc-ui/check-doc-alias-attr.rs [new file with mode: 0644]
src/test/rustdoc-ui/check-doc-alias-attr.stderr [new file with mode: 0644]
src/test/ui/abi/abi-sysv64-register-usage.rs
src/test/ui/align-with-extern-c-fn.rs
src/test/ui/assoc-lang-items.rs [new file with mode: 0644]
src/test/ui/assoc-lang-items.stderr [new file with mode: 0644]
src/test/ui/fn/fn-item-type.rs
src/test/ui/fn/fn-item-type.stderr
src/test/ui/glob-resolve1.rs
src/test/ui/glob-resolve1.stderr
src/test/ui/impl-trait/issue-69840.rs [new file with mode: 0644]
src/test/ui/infinite/infinite-instantiation.rs
src/test/ui/infinite/infinite-instantiation.stderr
src/test/ui/issues/issue-16441.rs
src/test/ui/issues/issue-26997.rs
src/test/ui/issues/issue-28600.rs
src/test/ui/issues/issue-38763.rs
src/test/ui/issues/issue-51907.rs
src/test/ui/issues/issue-67552.rs
src/test/ui/issues/issue-67552.stderr
src/test/ui/issues/issue-8727.rs
src/test/ui/issues/issue-8727.stderr
src/test/ui/lint/lint-ctypes-fn.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-fn.stderr [new file with mode: 0644]
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr [new file with mode: 0644]
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.rs
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.stderr
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr
src/test/ui/mir/mir_cast_fn_ret.rs
src/test/ui/mir/mir_codegen_calls.rs
src/test/ui/mir/mir_detects_invalid_ops.rs
src/test/ui/mir/mir_detects_invalid_ops.stderr
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/never_type/issue-51506.rs [new file with mode: 0644]
src/test/ui/never_type/issue-51506.stderr [new file with mode: 0644]
src/test/ui/parser/issue-62524.rs
src/test/ui/parser/issue-62524.stderr
src/test/ui/proc-macro/auxiliary/first-second.rs [new file with mode: 0644]
src/test/ui/proc-macro/auxiliary/recollect.rs [new file with mode: 0644]
src/test/ui/proc-macro/auxiliary/weird-hygiene.rs [new file with mode: 0644]
src/test/ui/proc-macro/capture-macro-rules-invoke.rs [new file with mode: 0644]
src/test/ui/proc-macro/macro-rules-derive.rs [new file with mode: 0644]
src/test/ui/proc-macro/macro-rules-derive.stderr [new file with mode: 0644]
src/test/ui/proc-macro/weird-hygiene.rs [new file with mode: 0644]
src/test/ui/range/issue-73553-misinterp-range-literal.rs [new file with mode: 0644]
src/test/ui/range/issue-73553-misinterp-range-literal.stderr [new file with mode: 0644]
src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
src/test/ui/recursion/recursion.rs
src/test/ui/recursion/recursion.stderr
src/test/ui/resolve/issue-21221-2.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/specialization/issue-44861.rs [new file with mode: 0644]
src/test/ui/specialization/issue-44861.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-59435.rs [new file with mode: 0644]
src/test/ui/specialization/issue-59435.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-73592-borrow_mut-through-deref.rs [new file with mode: 0644]
src/test/ui/typeck/issue-73592-borrow_mut-through-deref.stderr [new file with mode: 0644]
src/test/ui/utf8_idents.rs
src/test/ui/utf8_idents.stderr
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/clippy/.github/ISSUE_TEMPLATE.md [deleted file]
src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/config.yml [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md [new file with mode: 0644]
src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
src/tools/clippy/.github/driver.sh
src/tools/clippy/clippy_lints/src/consts.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/let_underscore.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops.rs
src/tools/clippy/clippy_lints/src/macro_use.rs
src/tools/clippy/clippy_lints/src/mem_replace.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs
src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
src/tools/clippy/clippy_lints/src/types.rs
src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
src/tools/clippy/clippy_lints/src/utils/author.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
src/tools/clippy/clippy_lints/src/utils/sugg.rs
src/tools/clippy/clippy_lints/src/utils/usage.rs
src/tools/clippy/clippy_lints/src/wildcard_imports.rs
src/tools/clippy/src/driver.rs
src/tools/clippy/src/lintlist/mod.rs
src/tools/clippy/src/main.rs
src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/blacklisted_name.rs
src/tools/clippy/tests/ui/blacklisted_name.stderr
src/tools/clippy/tests/ui/crashes/ice-5389.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/if_same_then_else.rs
src/tools/clippy/tests/ui/macro_use_imports.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/macro_use_imports.rs
src/tools/clippy/tests/ui/macro_use_imports.stderr
src/tools/clippy/tests/ui/redundant_pattern_matching.fixed
src/tools/clippy/tests/ui/redundant_pattern_matching.rs
src/tools/clippy/tests/ui/redundant_pattern_matching.stderr
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/repl_uninit.rs
src/tools/clippy/tests/ui/repl_uninit.stderr
src/tools/compiletest/src/json.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/read2.rs
src/tools/compiletest/src/runtest.rs
src/tools/rustdoc-js/tester.js
triagebot.toml

index 9b406d4a1f61c83da062b183816797bd6fcdceeb..8a0991059d5b26cd53ff61f393173976114c19dd 100644 (file)
@@ -4200,6 +4200,7 @@ dependencies = [
  "rustc_expand",
  "rustc_feature",
  "rustc_hir",
+ "rustc_index",
  "rustc_metadata",
  "rustc_middle",
  "rustc_session",
@@ -5404,15 +5405,15 @@ dependencies = [
 
 [[package]]
 name = "unicode-script"
-version = "0.4.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b2c5c29e805da6817f5af6a627d65adb045cebf05cccd5a3493d6109454391c"
+checksum = "58b33414ea8db4b7ea0343548dbdc31d27aef06beacf7044a87e564d9b0feb7d"
 
 [[package]]
 name = "unicode-security"
-version = "0.0.3"
+version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5f9011bbed9c13372bc8df618b55a38138445199caf3b61d432c6859c36dee0"
+checksum = "5d87c28edc5b263377e448d6cdcb935c06b95413d8013ba6fae470558ccab18f"
 dependencies = [
  "unicode-normalization",
  "unicode-script",
index 30cd9dfe71c446de63826bb4472627af45acc9db..4e7c00bece1544d409312ec93467beb62b5bd0cb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 30cd9dfe71c446de63826bb4472627af45acc9db
+Subproject commit 4e7c00bece1544d409312ec93467beb62b5bd0cb
index 5555a97f04ad7974ac6fb8fb47c267c4274adf4a..616962ad0dd80f34d8b802da038d0aed9dd691bb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5555a97f04ad7974ac6fb8fb47c267c4274adf4a
+Subproject commit 616962ad0dd80f34d8b802da038d0aed9dd691bb
index 5d40ba5c2515caffa7790cda621239dc21ef5a72..04d5d5d7ba624b6f5016298451f3a63d557f3260 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5d40ba5c2515caffa7790cda621239dc21ef5a72
+Subproject commit 04d5d5d7ba624b6f5016298451f3a63d557f3260
index 7aa82129aa23e7e181efbeb8da03a2a897ef6afc..6f94ccb48da6fa4ed0031290f21411cf789f7d5e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 7aa82129aa23e7e181efbeb8da03a2a897ef6afc
+Subproject commit 6f94ccb48da6fa4ed0031290f21411cf789f7d5e
index d10cbf1afab30b9bddff1aecd94bcec1b183da25..f1b560b9b968550dea1950fd4bba412e18190f5c 100644 (file)
 //! pub struct Foo;
 //!
 //! #[no_mangle]
+//! #[allow(improper_ctypes_definitions)]
 //! pub extern "C" fn foo_new() -> Box<Foo> {
 //!     Box::new(Foo)
 //! }
 //!
 //! #[no_mangle]
+//! #[allow(improper_ctypes_definitions)]
 //! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
 //! ```
 //!
index 2fcc8cc98737d4beb7c93346fd8e9196c9992f6a..34cacebe79636178c61c40dcb02af0d1511b3cfb 100644 (file)
@@ -488,7 +488,9 @@ struct MergeIter<K, V, I: Iterator<Item = (K, V)>> {
 }
 
 impl<K: Ord, V> BTreeMap<K, V> {
-    /// Makes a new empty BTreeMap with a reasonable choice for B.
+    /// Makes a new empty BTreeMap.
+    ///
+    /// Does not allocate anything on its own.
     ///
     /// # Examples
     ///
index fc2ec7908e82368e5c667a847a1abc2ab8a6765b..960af4bfda0533ee12d400bb1f359d51cd989b15 100644 (file)
@@ -1,7 +1,5 @@
 use super::*;
 
-use test;
-
 #[bench]
 #[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_push_back_100(b: &mut test::Bencher) {
index fc8a992e1701bf9d6d03ef623aea96e705509b97..1265d0e56b576ceed08c1f12091a4abd8053b043 100644 (file)
@@ -62,7 +62,7 @@
 use core::array::LengthAtMost32;
 use core::cmp::{self, Ordering};
 use core::fmt;
-use core::hash::{self, Hash};
+use core::hash::{Hash, Hasher};
 use core::intrinsics::{arith_offset, assume};
 use core::iter::{FromIterator, FusedIterator, TrustedLen};
 use core::marker::PhantomData;
@@ -1943,7 +1943,7 @@ fn clone_from(&mut self, other: &Vec<T>) {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Hash> Hash for Vec<T> {
     #[inline]
-    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+    fn hash<H: Hasher>(&self, state: &mut H) {
         Hash::hash(&**self, state)
     }
 }
index 5ff52a9a11b5a348bd543f2907130f52f63d833e..46ba0a279b7fff00462f9cb88309ab1a5f826f12 100644 (file)
@@ -445,3 +445,42 @@ fn from(small: $Small) -> Self {
 nzint_impl_from! { NonZeroU32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
 nzint_impl_from! { NonZeroU32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
 nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+
+macro_rules! nzint_impl_try_from_int {
+    ($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => {
+        #[$attr]
+        #[doc = $doc]
+        impl TryFrom<$Int> for $NonZeroInt {
+            type Error = TryFromIntError;
+
+            #[inline]
+            fn try_from(value: $Int) -> Result<Self, Self::Error> {
+                Self::new(value).ok_or(TryFromIntError(()))
+            }
+        }
+    };
+    ($Int: ty, $NonZeroInt: ty, #[$attr:meta]) => {
+        nzint_impl_try_from_int!($Int,
+                                 $NonZeroInt,
+                                 #[$attr],
+                                 concat!("Attempts to convert `",
+                                         stringify!($Int),
+                                         "` to `",
+                                         stringify!($NonZeroInt),
+                                         "`."));
+    }
+}
+
+// Int -> Non-zero Int
+nzint_impl_try_from_int! { u8, NonZeroU8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u16, NonZeroU16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u32, NonZeroU32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u64, NonZeroU64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u128, NonZeroU128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { usize, NonZeroUsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i8, NonZeroI8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i16, NonZeroI16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i32, NonZeroI32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i64, NonZeroI64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i128, NonZeroI128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
index 4074087e1e67f58b0a36d64b5d164760adcede83..5d09018759191806f8d157385aa68763a4cd94ca 100644 (file)
     /// implements `Copy`.
     ///
     /// If the actual type neither requires drop glue nor implements
-    /// `Copy`, then may return `true` or `false`.
+    /// `Copy`, then the return value of this function is unspecified.
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::mem::needs_drop`](../../std/mem/fn.needs_drop.html).
index 04c7789fa4ff498bad2e56e6aca49116f4137a31..2cdfee87a3546ab97637817a25f5c35744bc6959 100644 (file)
@@ -224,6 +224,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
 #[must_use = "closures are lazy and do nothing unless called"]
 pub trait FnOnce<Args> {
     /// The returned type after the call operator is used.
+    #[cfg_attr(not(bootstrap), lang = "fn_once_output")]
     #[stable(feature = "fn_once_output", since = "1.12.0")]
     type Output;
 
index 0227a66b8633a704137287e33ca8486b01dcade7..48aec6d718d3d3c0c7ac472c9b895cc159d3dea1 100644 (file)
@@ -1,3 +1,4 @@
+use core::convert::TryFrom;
 use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8};
 use core::option::Option::{self, None, Some};
 use std::mem::size_of;
@@ -176,3 +177,21 @@ fn test_nonzero_bitor_assign() {
     target |= 0;
     assert_eq!(target.get(), 0b1011_1111);
 }
+
+#[test]
+fn test_nonzero_from_int_on_success() {
+    assert_eq!(NonZeroU8::try_from(5), Ok(NonZeroU8::new(5).unwrap()));
+    assert_eq!(NonZeroU32::try_from(5), Ok(NonZeroU32::new(5).unwrap()));
+
+    assert_eq!(NonZeroI8::try_from(-5), Ok(NonZeroI8::new(-5).unwrap()));
+    assert_eq!(NonZeroI32::try_from(-5), Ok(NonZeroI32::new(-5).unwrap()));
+}
+
+#[test]
+fn test_nonzero_from_int_on_err() {
+    assert!(NonZeroU8::try_from(0).is_err());
+    assert!(NonZeroU32::try_from(0).is_err());
+
+    assert!(NonZeroI8::try_from(0).is_err());
+    assert!(NonZeroI32::try_from(0).is_err());
+}
index fd3e11858cef67719f1acb85a8d217d670573e0a..27056d5f934fdc1c4f503ab294ba7803dbab2d17 100644 (file)
@@ -21,6 +21,7 @@
 use core::any::Any;
 
 #[rustc_std_internal_symbol]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
 pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
     unreachable!()
 }
index f791fe82a27e7dcf7182111f50f0eda14ee53a8f..f361354da2ac2ff59081a778e10b4fcfb67edec6 100644 (file)
@@ -81,6 +81,7 @@
 mod dwarf;
 
 #[rustc_std_internal_symbol]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
 pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
     Box::into_raw(imp::cleanup(payload))
 }
index 8cfbd408e22b3878078f479eb88d249a2cfd929c..00665c4cafb6b4d24d23c180cddeecaa52cd0414 100644 (file)
@@ -253,7 +253,7 @@ fn lower_item_kind(
                 hir::ItemKind::Const(ty, body_id)
             }
             ItemKind::Fn(_, FnSig { ref decl, header }, ref generics, ref body) => {
-                let fn_def_id = self.resolver.definitions().local_def_id(id);
+                let fn_def_id = self.resolver.local_def_id(id);
                 self.with_new_scopes(|this| {
                     this.current_item = Some(ident.span);
 
@@ -342,7 +342,7 @@ fn lower_item_kind(
                 self_ty: ref ty,
                 items: ref impl_items,
             } => {
-                let def_id = self.resolver.definitions().local_def_id(id);
+                let def_id = self.resolver.local_def_id(id);
 
                 // Lower the "impl header" first. This ordering is important
                 // for in-band lifetimes! Consider `'a` here:
@@ -646,7 +646,7 @@ fn rebuild_vis(&mut self, vis: &hir::Visibility<'hir>) -> hir::Visibility<'hir>
     }
 
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
-        let def_id = self.resolver.definitions().local_def_id(i.id);
+        let def_id = self.resolver.local_def_id(i.id);
         hir::ForeignItem {
             hir_id: self.lower_node_id(i.id),
             ident: i.ident,
@@ -747,7 +747,7 @@ fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::Stru
     }
 
     fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> {
-        let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
+        let trait_item_def_id = self.resolver.local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
             AssocItemKind::Const(_, ref ty, ref default) => {
@@ -812,7 +812,7 @@ fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> {
-        let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
+        let impl_item_def_id = self.resolver.local_def_id(i.id);
 
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
@@ -1320,12 +1320,7 @@ pub(super) fn lower_generics_mut(
                                     if let Some(def_id) = def_id.as_local() {
                                         for param in &generics.params {
                                             if let GenericParamKind::Type { .. } = param.kind {
-                                                if def_id
-                                                    == self
-                                                        .resolver
-                                                        .definitions()
-                                                        .local_def_id(param.id)
-                                                {
+                                                if def_id == self.resolver.local_def_id(param.id) {
                                                     add_bounds
                                                         .entry(param.id)
                                                         .or_default()
index 335cc3e61040d5cf95b3c632c2272027f366a861..39b14ac4588326dd66ca3b520d5d4b3edb496381 100644 (file)
@@ -54,7 +54,7 @@
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ParamName};
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::config::nightly_options;
 use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::ParseSess;
@@ -205,6 +205,19 @@ fn resolve_str_path(
     fn next_node_id(&mut self) -> NodeId;
 
     fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
+
+    fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
+
+    fn local_def_id(&self, node: NodeId) -> LocalDefId;
+
+    fn create_def(
+        &mut self,
+        parent: LocalDefId,
+        node_id: ast::NodeId,
+        data: DefPathData,
+        expn_id: ExpnId,
+        span: Span,
+    ) -> LocalDefId;
 }
 
 type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
@@ -436,7 +449,7 @@ fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: LocalDefI
                 match tree.kind {
                     UseTreeKind::Simple(_, id1, id2) => {
                         for &id in &[id1, id2] {
-                            self.lctx.resolver.definitions().create_def_with_parent(
+                            self.lctx.resolver.create_def(
                                 owner,
                                 id,
                                 DefPathData::Misc,
@@ -488,7 +501,7 @@ fn visit_item(&mut self, item: &'tcx Item) {
                     | ItemKind::Enum(_, ref generics)
                     | ItemKind::TyAlias(_, ref generics, ..)
                     | ItemKind::Trait(_, _, ref generics, ..) => {
-                        let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
+                        let def_id = self.lctx.resolver.local_def_id(item.id);
                         let count = generics
                             .params
                             .iter()
@@ -564,7 +577,18 @@ fn visit_ty(&mut self, t: &'tcx Ty) {
             .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone()))
             .collect();
 
-        self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
+        let mut def_id_to_hir_id = IndexVec::default();
+
+        for (node_id, hir_id) in self.node_id_to_hir_id.into_iter_enumerated() {
+            if let Some(def_id) = self.resolver.opt_local_def_id(node_id) {
+                if def_id_to_hir_id.len() <= def_id.index() {
+                    def_id_to_hir_id.resize(def_id.index() + 1, None);
+                }
+                def_id_to_hir_id[def_id] = hir_id;
+            }
+        }
+
+        self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
 
         hir::Crate {
             item: hir::CrateItem { module, attrs, span: c.span },
@@ -628,7 +652,7 @@ fn with_hir_id_owner<T>(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T
             .item_local_id_counters
             .insert(owner, HIR_ID_COUNTER_LOCKED)
             .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
-        let def_id = self.resolver.definitions().local_def_id(owner);
+        let def_id = self.resolver.local_def_id(owner);
         self.current_hir_id_owner.push((def_id, counter));
         let ret = f(self);
         let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap();
@@ -671,8 +695,8 @@ fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> hi
             debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
 
             *local_id_counter += 1;
-            let owner = this.resolver.definitions().opt_local_def_id(owner).expect(
-                "you forgot to call `create_def_with_parent` or are lowering node-IDs \
+            let owner = this.resolver.opt_local_def_id(owner).expect(
+                "you forgot to call `create_def` or are lowering node-IDs \
                  that do not belong to the current owner",
             );
 
@@ -800,7 +824,7 @@ fn lifetime_to_generic_param(
         };
 
         // Add a definition for the in-band lifetime def.
-        self.resolver.definitions().create_def_with_parent(
+        self.resolver.create_def(
             parent_def_id,
             node_id,
             DefPathData::LifetimeNs(str_name),
@@ -1088,7 +1112,7 @@ fn lower_assoc_ty_constraint(
 
                     let impl_trait_node_id = self.resolver.next_node_id();
                     let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
-                    self.resolver.definitions().create_def_with_parent(
+                    self.resolver.create_def(
                         parent_def_id,
                         impl_trait_node_id,
                         DefPathData::ImplTrait,
@@ -1154,7 +1178,7 @@ fn lower_generic_arg(
                             let node_id = self.resolver.next_node_id();
 
                             // Add a definition for the in-band const def.
-                            self.resolver.definitions().create_def_with_parent(
+                            self.resolver.create_def(
                                 parent_def_id,
                                 node_id,
                                 DefPathData::AnonConst,
@@ -1339,7 +1363,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                     }
                     ImplTraitContext::Universal(in_band_ty_params) => {
                         // Add a definition for the in-band `Param`.
-                        let def_id = self.resolver.definitions().local_def_id(def_node_id);
+                        let def_id = self.resolver.local_def_id(def_node_id);
 
                         let hir_bounds = self.lower_param_bounds(
                             bounds,
@@ -1428,7 +1452,7 @@ fn lower_opaque_impl_trait(
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let opaque_ty_def_id = self.resolver.definitions().local_def_id(opaque_ty_node_id);
+        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
 
         self.allocate_hir_id_counter(opaque_ty_node_id);
 
@@ -1620,7 +1644,7 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
                     let def_node_id = self.context.resolver.next_node_id();
                     let hir_id =
                         self.context.lower_node_id_with_owner(def_node_id, self.opaque_ty_id);
-                    self.context.resolver.definitions().create_def_with_parent(
+                    self.context.resolver.create_def(
                         self.parent,
                         def_node_id,
                         DefPathData::LifetimeNs(name.ident().name),
@@ -1870,7 +1894,7 @@ fn lower_async_fn_ret_ty(
 
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let opaque_ty_def_id = self.resolver.definitions().local_def_id(opaque_ty_node_id);
+        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
 
         self.allocate_hir_id_counter(opaque_ty_node_id);
 
index f51439f89ffbe9a5f2cfcba73294339095e0eb0b..f92e40ed6ffabf0541c03cfbb7093214a2c94412 100644 (file)
@@ -2,7 +2,6 @@
 
 use rustc_ast::ast;
 use rustc_ast::with_default_globals;
-use rustc_span;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::Ident;
 
index 868ce876a8192e76a0bbdf315cf821279794dce8..54271d3dd04919e61a9fad93c31e8d1007ba2c59 100644 (file)
@@ -23,6 +23,7 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
 use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
 use rustc_target::spec::{CodeModel, RelocModel};
 
@@ -140,7 +141,7 @@ pub fn target_machine_factory(
     // lower atomic operations to single-threaded operations.
     if singlethread
         && sess.target.target.llvm_target.contains("wasm32")
-        && features.iter().any(|s| *s == "+atomics")
+        && sess.target_features.contains(&sym::atomics)
     {
         singlethread = false;
     }
index e43c814a6125ee5e4e90b2d7ea6b03ff50e3c451..130c0cf1877c667c02a0258961eb1b6bb1e63e82 100644 (file)
@@ -23,7 +23,6 @@
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
-use rustc_span::Symbol;
 use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive};
 use rustc_target::spec::PanicStrategy;
 
@@ -141,26 +140,20 @@ fn codegen_intrinsic_call(
                 self.call(llfn, &[], None)
             }
             "count_code_region" => {
-                if let ty::InstanceDef::Item(fn_def_id) = caller_instance.def {
-                    let caller_fn_path = tcx.def_path_str(fn_def_id);
-                    debug!(
-                        "count_code_region to llvm.instrprof.increment(fn_name={})",
-                        caller_fn_path
-                    );
-
-                    // FIXME(richkadel): (1) Replace raw function name with mangled function name;
-                    // (2) Replace hardcoded `1234` in `hash` with a computed hash (as discussed in)
-                    // the MCP (compiler-team/issues/278); and replace the hardcoded `1` for
-                    // `num_counters` with the actual number of counters per function (when the
-                    // changes are made to inject more than one counter per function).
-                    let (fn_name, _len_val) = self.const_str(Symbol::intern(&caller_fn_path));
-                    let index = args[0].immediate();
-                    let hash = self.const_u64(1234);
-                    let num_counters = self.const_u32(1);
-                    self.instrprof_increment(fn_name, hash, num_counters, index)
-                } else {
-                    bug!("intrinsic count_code_region: no src.instance");
-                }
+                // FIXME(richkadel): The current implementation assumes the MIR for the given
+                // caller_instance represents a single function. Validate and/or correct if inlining
+                // and/or monomorphization invalidates these assumptions.
+                let coverage_data = tcx.coverage_data(caller_instance.def_id());
+                let mangled_fn = tcx.symbol_name(caller_instance);
+                let (mangled_fn_name, _len_val) = self.const_str(mangled_fn.name);
+                let hash = self.const_u64(coverage_data.hash);
+                let num_counters = self.const_u32(coverage_data.num_counters);
+                let index = args[0].immediate();
+                debug!(
+                    "count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
+                    mangled_fn.name, hash, num_counters, index
+                );
+                self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
             }
             "va_start" => self.va_start(args[0].immediate()),
             "va_end" => self.va_end(args[0].immediate()),
index 6c995be913c9e94c5528eef7a4bd6d91f75d392b..a34029410784ac33efd70849d843fe2cb6984bcc 100644 (file)
@@ -140,7 +140,12 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
 // The third parameter is for env vars, used on windows to set up the
 // path for MSVC to find its DLLs, and gcc to find its bundled
 // toolchain
-fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
+fn get_linker(
+    sess: &Session,
+    linker: &Path,
+    flavor: LinkerFlavor,
+    self_contained: bool,
+) -> Command {
     let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
 
     // If our linker looks like a batch script on Windows then to execute this
@@ -199,7 +204,7 @@ fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
 
     // The compiler's sysroot often has some bundled tools, so add it to the
     // PATH for the child.
-    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
+    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
     let mut msvc_changed_path = false;
     if sess.target.target.options.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
@@ -551,19 +556,25 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
                 "Linker does not support -static-pie command line option. Retrying with -static instead."
             );
             // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
-            let fallback = crt_objects_fallback(sess, crate_type);
+            let self_contained = crt_objects_fallback(sess, crate_type);
             let opts = &sess.target.target.options;
-            let pre_objects =
-                if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
-            let post_objects =
-                if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+            let pre_objects = if self_contained {
+                &opts.pre_link_objects_fallback
+            } else {
+                &opts.pre_link_objects
+            };
+            let post_objects = if self_contained {
+                &opts.post_link_objects_fallback
+            } else {
+                &opts.post_link_objects
+            };
             let get_objects = |objects: &CrtObjects, kind| {
                 objects
                     .get(&kind)
                     .iter()
                     .copied()
                     .flatten()
-                    .map(|obj| get_object_file_path(sess, obj).into_os_string())
+                    .map(|obj| get_object_file_path(sess, obj, self_contained).into_os_string())
                     .collect::<Vec<_>>()
             };
             let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe);
@@ -1066,9 +1077,11 @@ fn probe(sess: &Session) -> Option<PathBuf> {
     }
 }
 
-fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
+fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf {
     // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details
-    if sess.target.target.llvm_target.contains("windows-gnu") {
+    if sess.opts.debugging_opts.link_self_contained.is_none()
+        && sess.target.target.llvm_target.contains("windows-gnu")
+    {
         if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
             let file_path = compiler_libs_path.join(name);
             if file_path.exists() {
@@ -1081,9 +1094,12 @@ fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
     if file_path.exists() {
         return file_path;
     }
-    let file_path = fs.get_selfcontained_lib_path().join(name);
-    if file_path.exists() {
-        return file_path;
+    // Special directory with objects used only in self-contained linkage mode
+    if self_contained {
+        let file_path = fs.get_self_contained_lib_path().join(name);
+        if file_path.exists() {
+            return file_path;
+        }
     }
     for search_path in fs.search_paths() {
         let file_path = search_path.dir.join(name);
@@ -1268,6 +1284,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
 /// Whether we link to our own CRT objects instead of relying on gcc to pull them.
 /// We only provide such support for a very limited number of targets.
 fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
+    if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained {
+        return self_contained;
+    }
+
     match sess.target.target.options.crt_objects_fallback {
         // FIXME: Find a better heuristic for "native musl toolchain is available",
         // based on host and linker path, for example.
@@ -1287,12 +1307,13 @@ fn add_pre_link_objects(
     cmd: &mut dyn Linker,
     sess: &Session,
     link_output_kind: LinkOutputKind,
-    fallback: bool,
+    self_contained: bool,
 ) {
     let opts = &sess.target.target.options;
-    let objects = if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
+    let objects =
+        if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
-        cmd.add_object(&get_object_file_path(sess, obj));
+        cmd.add_object(&get_object_file_path(sess, obj, self_contained));
     }
 }
 
@@ -1301,12 +1322,13 @@ fn add_post_link_objects(
     cmd: &mut dyn Linker,
     sess: &Session,
     link_output_kind: LinkOutputKind,
-    fallback: bool,
+    self_contained: bool,
 ) {
     let opts = &sess.target.target.options;
-    let objects = if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+    let objects =
+        if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
-        cmd.add_object(&get_object_file_path(sess, obj));
+        cmd.add_object(&get_object_file_path(sess, obj, self_contained));
     }
 }
 
@@ -1468,9 +1490,12 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'
 }
 
 /// Add sysroot and other globally set directories to the directory search list.
-fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
+fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
     // Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details.
-    if cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") {
+    if sess.opts.debugging_opts.link_self_contained.is_none()
+        && cfg!(windows)
+        && sess.target.target.llvm_target.contains("windows-gnu")
+    {
         if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
             cmd.include_path(&compiler_libs_path);
         }
@@ -1481,8 +1506,11 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
     let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
     cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
 
-    let lib_path = sess.target_filesearch(PathKind::All).get_selfcontained_lib_path();
-    cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+    // Special directory with libraries used only in self-contained linkage mode
+    if self_contained {
+        let lib_path = sess.target_filesearch(PathKind::All).get_self_contained_lib_path();
+        cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+    }
 }
 
 /// Add options making relocation sections in the produced ELF files read-only
@@ -1545,13 +1573,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     codegen_results: &CodegenResults,
     target_cpu: &str,
 ) -> Command {
-    let base_cmd = get_linker(sess, path, flavor);
+    let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
+    let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback);
     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
     // to the linker args construction.
     assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp");
     let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
     let link_output_kind = link_output_kind(sess, crate_type);
-    let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
 
     // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
     add_pre_link_args(cmd, sess, flavor);
@@ -1597,7 +1625,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     // FIXME: Order-dependent, at least relatively to other args adding searh directories.
-    add_library_search_dirs(cmd, sess);
+    add_library_search_dirs(cmd, sess, crt_objects_fallback);
 
     // OBJECT-FILES-YES
     add_local_crate_regular_objects(cmd, codegen_results);
index 6011d422ca682c174549f72432a485e6e97f676a..d6ef94bfd1727352d154943afa1ef06bbf1510dd 100644 (file)
@@ -1,6 +1,7 @@
 use super::archive;
 use super::command::Command;
 use super::symbol_export;
+use rustc_span::symbol::sym;
 
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
@@ -1036,9 +1037,7 @@ fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a>
         //
         // * `--export=*tls*` - when `#[thread_local]` symbols are used these
         //   symbols are how the TLS segments are initialized and configured.
-        let atomics = sess.opts.cg.target_feature.contains("+atomics")
-            || sess.target.target.options.features.contains("+atomics");
-        if atomics {
+        if sess.target_features.contains(&sym::atomics) {
             cmd.arg("--shared-memory");
             cmd.arg("--max-memory=1073741824");
             cmd.arg("--import-memory");
index 39afb3d82ff5aae9ef943718051b9709ff5229c5..53d831749ceb7b401a66008222d301f96dcbed7c 100644 (file)
@@ -358,7 +358,6 @@ pub fn lock_mut(&self) -> LockGuard<'_, T> {
         use parking_lot::Mutex as InnerLock;
         use parking_lot::RwLock as InnerRwLock;
 
-        use std;
         use std::thread;
         pub use rayon::{join, scope};
 
index ccea041699ee18c6ff85acef69d34c94c5e7c739..b45ab0f80ffac4a4cd2c4b3b1c4068d3b0b32a26 100644 (file)
@@ -307,6 +307,7 @@ pub fn run_compiler(
                         compiler.output_file().as_ref().map(|p| &**p),
                     );
                 }
+                trace!("finished pretty-printing");
                 return early_exit();
             }
 
index db8258a77863b8c3d3043fa656dd8267f2decdfe..968f7c8e273a36ae6a557085f42c2476e5662bbe 100644 (file)
@@ -866,10 +866,23 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Result<Nonterminal, (
 }
 
 fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a, Nonterminal> {
+    // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
+    // needs to have them force-captured here.
+    // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
+    // which requires having captured tokens available. Since we cannot determine
+    // in advance whether or not a proc-macro will be (transitively) invoked,
+    // we always capture tokens for any `Nonterminal` which needs them.
     Ok(match name {
-        sym::item => match p.parse_item()? {
-            Some(i) => token::NtItem(i),
-            None => return Err(p.struct_span_err(p.token.span, "expected an item keyword")),
+        sym::item => match p.collect_tokens(|this| this.parse_item())? {
+            (Some(mut item), tokens) => {
+                // If we captured tokens during parsing (due to outer attributes),
+                // use those.
+                if item.tokens.is_none() {
+                    item.tokens = Some(tokens);
+                }
+                token::NtItem(item)
+            }
+            (None, _) => return Err(p.struct_span_err(p.token.span, "expected an item keyword")),
         },
         sym::block => token::NtBlock(p.parse_block()?),
         sym::stmt => match p.parse_stmt()? {
@@ -877,7 +890,15 @@ fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a,
             None => return Err(p.struct_span_err(p.token.span, "expected a statement")),
         },
         sym::pat => token::NtPat(p.parse_pat(None)?),
-        sym::expr => token::NtExpr(p.parse_expr()?),
+        sym::expr => {
+            let (mut expr, tokens) = p.collect_tokens(|this| this.parse_expr())?;
+            // If we captured tokens during parsing (due to outer attributes),
+            // use those.
+            if expr.tokens.is_none() {
+                expr.tokens = Some(tokens);
+            }
+            token::NtExpr(expr)
+        }
         sym::literal => token::NtLiteral(p.parse_literal_maybe_minus()?),
         sym::ty => token::NtTy(p.parse_ty()?),
         // this could be handled like a token, since it is one
index 5755a3db92ac1400fb9210de30cccea8dfb8aacf..79b70682739326b1ea18c4254e7cbc83fbade8d1 100644 (file)
@@ -8,14 +8,12 @@
 use crate::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use crate::hir;
 
-use rustc_ast::ast;
 use rustc_ast::crate_disambiguator::CrateDisambiguator;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_index::vec::IndexVec;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
 
 use log::debug;
 use std::fmt::Write;
@@ -73,17 +71,12 @@ pub fn size(&self) -> usize {
 }
 
 /// The definition table containing node definitions.
-/// It holds the `DefPathTable` for local `DefId`s/`DefPath`s and it also stores a
-/// mapping from `NodeId`s to local `DefId`s.
-#[derive(Clone, Default)]
+/// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s.
+/// It also stores mappings to convert `LocalDefId`s to/from `HirId`s.
+#[derive(Clone)]
 pub struct Definitions {
     table: DefPathTable,
 
-    def_id_to_span: IndexVec<LocalDefId, Span>,
-
-    node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
-    def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
-
     // FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners.
     pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
     /// The reverse mapping of `def_id_to_hir_id`.
@@ -94,12 +87,6 @@ pub struct Definitions {
     parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
     /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
     expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
-    next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
-    /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
-    /// we know what parent node that fragment should be attached to thanks to this table.
-    invocation_parents: FxHashMap<ExpnId, LocalDefId>,
-    /// Indices of unnamed struct or variant fields with unresolved attributes.
-    placeholder_field_indices: FxHashMap<ast::NodeId, usize>,
 }
 
 /// A unique identifier that we can use to lookup a definition
@@ -319,16 +306,6 @@ pub fn def_path(&self, id: LocalDefId) -> DefPath {
         })
     }
 
-    #[inline]
-    pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<LocalDefId> {
-        self.node_id_to_def_id.get(&node).copied()
-    }
-
-    #[inline]
-    pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId {
-        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
-    }
-
     #[inline]
     pub fn as_local_hir_id(&self, def_id: LocalDefId) -> hir::HirId {
         self.local_def_id_to_hir_id(def_id)
@@ -349,18 +326,8 @@ pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefI
         self.hir_id_to_def_id.get(&hir_id).copied()
     }
 
-    /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
-    #[inline]
-    pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
-        if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
-    }
-
     /// Adds a root definition (no parent) and a few other reserved definitions.
-    pub fn create_root_def(
-        &mut self,
-        crate_name: &str,
-        crate_disambiguator: CrateDisambiguator,
-    ) -> LocalDefId {
+    pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
         let key = DefKey {
             parent: None,
             disambiguated_data: DisambiguatedDefPathData {
@@ -372,52 +339,39 @@ pub fn create_root_def(
         let parent_hash = DefKey::root_parent_stable_hash(crate_name, crate_disambiguator);
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
-        // Create the definition.
-        let root = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
+        // Create the root definition.
+        let mut table = DefPathTable::default();
+        let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
         assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
 
-        assert_eq!(self.def_id_to_node_id.push(ast::CRATE_NODE_ID), root);
-        assert_eq!(self.def_id_to_span.push(rustc_span::DUMMY_SP), root);
-
-        self.node_id_to_def_id.insert(ast::CRATE_NODE_ID, root);
-        self.set_invocation_parent(ExpnId::root(), root);
+        Definitions {
+            table,
+            def_id_to_hir_id: Default::default(),
+            hir_id_to_def_id: Default::default(),
+            expansions_that_defined: Default::default(),
+            parent_modules_of_macro_defs: Default::default(),
+        }
+    }
 
-        root
+    /// Retrieves the root definition.
+    pub fn get_root_def(&self) -> LocalDefId {
+        LocalDefId { local_def_index: CRATE_DEF_INDEX }
     }
 
     /// Adds a definition with a parent definition.
-    pub fn create_def_with_parent(
+    pub fn create_def(
         &mut self,
         parent: LocalDefId,
-        node_id: ast::NodeId,
         data: DefPathData,
         expn_id: ExpnId,
-        span: Span,
+        mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
     ) -> LocalDefId {
-        debug!(
-            "create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
-            parent, node_id, data
-        );
-
-        assert!(
-            !self.node_id_to_def_id.contains_key(&node_id),
-            "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
-            node_id,
-            data,
-            self.table.def_key(self.node_id_to_def_id[&node_id].local_def_index),
-        );
+        debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
 
         // The root node must be created with `create_root_def()`.
         assert!(data != DefPathData::CrateRoot);
 
-        // Find the next free disambiguator for this key.
-        let disambiguator = {
-            let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
-            let disambiguator = *next_disamb;
-            *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
-            disambiguator
-        };
-
+        let disambiguator = next_disambiguator(parent, data);
         let key = DefKey {
             parent: Some(parent.local_def_index),
             disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
@@ -426,22 +380,11 @@ pub fn create_def_with_parent(
         let parent_hash = self.table.def_path_hash(parent.local_def_index);
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
-        debug!("create_def_with_parent: after disambiguation, key = {:?}", key);
+        debug!("create_def: after disambiguation, key = {:?}", key);
 
         // Create the definition.
         let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
 
-        assert_eq!(self.def_id_to_node_id.push(node_id), def_id);
-        assert_eq!(self.def_id_to_span.push(span), def_id);
-
-        // Some things for which we allocate `LocalDefId`s don't correspond to
-        // anything in the AST, so they don't have a `NodeId`. For these cases
-        // we don't need a mapping from `NodeId` to `LocalDefId`.
-        if node_id != ast::DUMMY_NODE_ID {
-            debug!("create_def_with_parent: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
-            self.node_id_to_def_id.insert(node_id, def_id);
-        }
-
         if expn_id != ExpnId::root() {
             self.expansions_that_defined.insert(def_id, expn_id);
         }
@@ -449,32 +392,24 @@ pub fn create_def_with_parent(
         def_id
     }
 
-    /// Initializes the `ast::NodeId` to `HirId` mapping once it has been generated during
+    /// Initializes the `LocalDefId` to `HirId` mapping once it has been generated during
     /// AST to HIR lowering.
-    pub fn init_node_id_to_hir_id_mapping(
+    pub fn init_def_id_to_hir_id_mapping(
         &mut self,
-        mapping: IndexVec<ast::NodeId, Option<hir::HirId>>,
+        mapping: IndexVec<LocalDefId, Option<hir::HirId>>,
     ) {
         assert!(
             self.def_id_to_hir_id.is_empty(),
             "trying to initialize `LocalDefId` <-> `HirId` mappings twice"
         );
 
-        self.def_id_to_hir_id = self
-            .def_id_to_node_id
-            .iter()
-            .map(|&node_id| mapping.get(node_id).and_then(|&hir_id| hir_id))
-            .collect();
-
         // Build the reverse mapping of `def_id_to_hir_id`.
         self.hir_id_to_def_id = mapping
-            .into_iter_enumerated()
-            .filter_map(|(node_id, hir_id)| {
-                hir_id.and_then(|hir_id| {
-                    self.node_id_to_def_id.get(&node_id).map(|&def_id| (hir_id, def_id))
-                })
-            })
+            .iter_enumerated()
+            .filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
             .collect();
+
+        self.def_id_to_hir_id = mapping;
     }
 
     pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
@@ -488,30 +423,6 @@ pub fn parent_module_of_macro_def(&self, expn_id: ExpnId) -> DefId {
     pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
         self.parent_modules_of_macro_defs.insert(expn_id, module);
     }
-
-    pub fn invocation_parent(&self, invoc_id: ExpnId) -> LocalDefId {
-        self.invocation_parents[&invoc_id]
-    }
-
-    pub fn set_invocation_parent(&mut self, invoc_id: ExpnId, parent: LocalDefId) {
-        let old_parent = self.invocation_parents.insert(invoc_id, parent);
-        assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
-    }
-
-    pub fn placeholder_field_index(&self, node_id: ast::NodeId) -> usize {
-        self.placeholder_field_indices[&node_id]
-    }
-
-    pub fn set_placeholder_field_index(&mut self, node_id: ast::NodeId, index: usize) {
-        let old_index = self.placeholder_field_indices.insert(node_id, index);
-        assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
-    }
-
-    pub fn lint_node_id(&mut self, expn_id: ExpnId) -> ast::NodeId {
-        self.invocation_parents
-            .get(&expn_id)
-            .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
-    }
 }
 
 impl DefPathData {
index 7d1cb7738c35e71a8b31065b8933209fc5892311..f3dfec7ca72150386063bb74dacc5dd9df1508a1 100644 (file)
@@ -1511,13 +1511,7 @@ fn is_range_path(path: &Path<'_>) -> bool {
     // Check whether a span corresponding to a range expression is a
     // range literal, rather than an explicit struct or `new()` call.
     fn is_lit(sm: &SourceMap, span: &Span) -> bool {
-        let end_point = sm.end_point(*span);
-
-        if let Ok(end_string) = sm.span_to_snippet(end_point) {
-            !(end_string.ends_with('}') || end_string.ends_with(')'))
-        } else {
-            false
-        }
+        sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
     };
 
     match expr.kind {
index 091ded6d74d0feb291a9a06bdb03f894cac21fc3..cd6f034f7a5dabce70fd976ca2257838637050a7 100644 (file)
@@ -25,7 +25,7 @@
 // So you probably just want to nip down to the end.
 macro_rules! language_item_table {
     (
-        $( $variant:ident, $name:expr, $method:ident, $target:path; )*
+        $( $variant:ident, $name:expr, $method:ident, $target:expr; )*
     ) => {
 
         enum_from_u32! {
@@ -207,6 +207,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     FnMutTraitLangItem,          "fn_mut",             fn_mut_trait,            Target::Trait;
     FnOnceTraitLangItem,         "fn_once",            fn_once_trait,           Target::Trait;
 
+    FnOnceOutputLangItem,        "fn_once_output",     fn_once_output,          Target::AssocTy;
+
     FutureTraitLangItem,         "future_trait",       future_trait,            Target::Trait;
     GeneratorStateLangItem,      "generator_state",    gen_state,               Target::Enum;
     GeneratorTraitLangItem,      "generator",          gen_trait,               Target::Trait;
index 9cfa11dd7c813ff7ffdb2aeab7847b821fbdb939..7fdcbd31df3c5085663428ea3fb2c1cafaeff250 100644 (file)
@@ -1256,7 +1256,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => {
                 let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
                 let mut values = self.cmp_fn_sig(&sig1, sig2);
-                values.0.push_normal(format!(
+                values.0.push_highlighted(format!(
                     " {{{}}}",
                     self.tcx.def_path_str_with_substs(*did1, substs1)
                 ));
index 5aad64f84cee3ac9368307f318e52ecedbc7ac5c..920cc6021e68781d3933c7c697cc616019095c8f 100644 (file)
@@ -202,6 +202,7 @@ pub fn run_compiler_in_existing_thread_pool<R>(
 }
 
 pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
+    log::trace!("run_compiler");
     let stderr = config.stderr.take();
     util::spawn_thread_pool(
         config.opts.edition,
index 1ed9bc3f1f509d0ac20144cf5cb5246a7ee282d3..e9a4119f4a3332e43edb5890a25d87c8d61ca9eb 100644 (file)
@@ -101,6 +101,7 @@ pub fn configure_and_expand(
     krate: ast::Crate,
     crate_name: &str,
 ) -> Result<(ast::Crate, BoxedResolver)> {
+    log::trace!("configure_and_expand");
     // Currently, we ignore the name resolution data structures for the purposes of dependency
     // tracking. Instead we will run name resolution and include its output in the hash of each
     // item, much like we do for macro expansion. In other words, the hash reflects not just
@@ -230,6 +231,7 @@ fn configure_and_expand_inner<'a>(
     resolver_arenas: &'a ResolverArenas<'a>,
     metadata_loader: &'a MetadataLoaderDyn,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
+    log::trace!("configure_and_expand_inner");
     pre_expansion_lint(sess, lint_store, &krate);
 
     let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
@@ -357,6 +359,7 @@ fn configure_and_expand_inner<'a>(
         should_loop |= true;
     }
     if should_loop {
+        log::debug!("replacing bodies with loop {{}}");
         util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
     }
 
@@ -734,7 +737,10 @@ pub fn create_global_ctxt<'tcx>(
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
 ) -> QueryContext<'tcx> {
     let sess = &compiler.session();
-    let defs: &'tcx Definitions = arena.alloc(mem::take(&mut resolver_outputs.definitions));
+    let defs: &'tcx Definitions = arena.alloc(mem::replace(
+        &mut resolver_outputs.definitions,
+        Definitions::new(crate_name, sess.local_crate_disambiguator()),
+    ));
 
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
index 283be165c192c17ddd07d197bf27d794a06936fc..4a41c3e97cafc3c99ee59ad811c8d9a01688b9ac 100644 (file)
@@ -169,6 +169,7 @@ pub fn crate_name(&self) -> Result<&Query<String>> {
     pub fn expansion(
         &self,
     ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
+        log::trace!("expansion");
         self.expansion.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let (krate, lint_store) = self.register_plugins()?.take();
index ada6f2a9381dc3db719a5f92b9fa18b1022dd084..58c15257326aeb20481869f3a161972b448d5e42 100644 (file)
@@ -10,7 +10,7 @@ path = "lib.rs"
 
 [dependencies]
 log = "0.4"
-unicode-security = "0.0.3"
+unicode-security = "0.0.5"
 rustc_middle = { path = "../librustc_middle" }
 rustc_ast_pretty = { path = "../librustc_ast_pretty" }
 rustc_attr = { path = "../librustc_attr" }
index ca2ca3145abc8180391a527980dd8e8ddcc4cafe..b39abe7b411bbad607cc3a4cb12e330bbccd0ac3 100644 (file)
@@ -167,7 +167,8 @@ macro_rules! late_lint_mod_passes {
             $args,
             [
                 HardwiredLints: HardwiredLints,
-                ImproperCTypes: ImproperCTypes,
+                ImproperCTypesDeclarations: ImproperCTypesDeclarations,
+                ImproperCTypesDefinitions: ImproperCTypesDefinitions,
                 VariantSizeDifferences: VariantSizeDifferences,
                 BoxPointers: BoxPointers,
                 PathStatements: PathStatements,
index 064b0255397ce20a3cdfe7fe46fb99d683f84e22..30dbd069c29bd2d847050b2955c477997040fdc0 100644 (file)
@@ -1,9 +1,7 @@
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast::ast;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::{Ident, SymbolStr};
-use std::hash::{Hash, Hasher};
-use std::ops::Deref;
+use rustc_span::symbol::SymbolStr;
 
 declare_lint! {
     pub NON_ASCII_IDENTS,
     crate_level_only
 }
 
-// FIXME: Change this to warn.
 declare_lint! {
     pub CONFUSABLE_IDENTS,
-    Allow,
+    Warn,
     "detects visually confusable pairs between identifiers",
     crate_level_only
 }
 
-declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]);
-
-enum CowBoxSymStr {
-    Interned(SymbolStr),
-    Owned(Box<str>),
-}
-
-impl Deref for CowBoxSymStr {
-    type Target = str;
-
-    fn deref(&self) -> &str {
-        match self {
-            CowBoxSymStr::Interned(interned) => interned,
-            CowBoxSymStr::Owned(ref owned) => owned,
-        }
-    }
-}
-
-impl Hash for CowBoxSymStr {
-    #[inline]
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        Hash::hash(&**self, state)
-    }
-}
-
-impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
-    #[inline]
-    fn eq(&self, other: &CowBoxSymStr) -> bool {
-        PartialEq::eq(&**self, &**other)
-    }
-}
-
-impl Eq for CowBoxSymStr {}
-
-fn calc_skeleton(symbol_str: SymbolStr, buffer: &'_ mut String) -> CowBoxSymStr {
-    use std::mem::swap;
-    use unicode_security::confusable_detection::skeleton;
-    buffer.clear();
-    buffer.extend(skeleton(&symbol_str));
-    if symbol_str == *buffer {
-        CowBoxSymStr::Interned(symbol_str)
-    } else {
-        let mut owned = String::new();
-        swap(buffer, &mut owned);
-        CowBoxSymStr::Owned(owned.into_boxed_str())
-    }
-}
-
-fn is_in_ascii_confusable_closure(c: char) -> bool {
-    // FIXME: move this table to `unicode_security` crate.
-    // data here corresponds to Unicode 13.
-    const ASCII_CONFUSABLE_CLOSURE: &[(u64, u64)] = &[(0x00, 0x7f), (0xba, 0xba), (0x2080, 0x2080)];
-    let c = c as u64;
-    for &(range_start, range_end) in ASCII_CONFUSABLE_CLOSURE {
-        if c >= range_start && c <= range_end {
-            return true;
-        }
-    }
-    false
+declare_lint! {
+    pub MIXED_SCRIPT_CONFUSABLES,
+    Warn,
+    "detects Unicode scripts whose mixed script confusables codepoints are solely used",
+    crate_level_only
 }
 
-fn is_in_ascii_confusable_closure_relevant_list(c: char) -> bool {
-    // FIXME: move this table to `unicode_security` crate.
-    // data here corresponds to Unicode 13.
-    const ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST: &[u64] = &[
-        0x22, 0x25, 0x27, 0x2f, 0x30, 0x31, 0x49, 0x4f, 0x60, 0x6c, 0x6d, 0x6e, 0x72, 0x7c, 0xba,
-        0x2080,
-    ];
-    let c = c as u64;
-    for &item in ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST {
-        if c == item {
-            return true;
-        }
-    }
-    false
-}
+declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS, MIXED_SCRIPT_CONFUSABLES]);
 
 impl EarlyLintPass for NonAsciiIdents {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
         use rustc_session::lint::Level;
-        if cx.builder.lint_level(CONFUSABLE_IDENTS).0 == Level::Allow {
+        use rustc_span::Span;
+        use std::collections::BTreeMap;
+        use unicode_security::GeneralSecurityProfile;
+        use utils::CowBoxSymStr;
+
+        let check_non_ascii_idents = cx.builder.lint_level(NON_ASCII_IDENTS).0 != Level::Allow;
+        let check_uncommon_codepoints =
+            cx.builder.lint_level(UNCOMMON_CODEPOINTS).0 != Level::Allow;
+        let check_confusable_idents = cx.builder.lint_level(CONFUSABLE_IDENTS).0 != Level::Allow;
+        let check_mixed_script_confusables =
+            cx.builder.lint_level(MIXED_SCRIPT_CONFUSABLES).0 != Level::Allow;
+
+        if !check_non_ascii_idents
+            && !check_uncommon_codepoints
+            && !check_confusable_idents
+            && !check_mixed_script_confusables
+        {
             return;
         }
+
+        let mut has_non_ascii_idents = false;
         let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
-        let mut symbol_strs_and_spans = Vec::with_capacity(symbols.len());
-        let mut in_fast_path = true;
-        for (symbol, sp) in symbols.iter() {
-            // fast path
+        for (symbol, &sp) in symbols.iter() {
             let symbol_str = symbol.as_str();
-            if !symbol_str.chars().all(is_in_ascii_confusable_closure) {
-                // fallback to slow path.
-                symbol_strs_and_spans.clear();
-                in_fast_path = false;
-                break;
+            if symbol_str.is_ascii() {
+                continue;
             }
-            if symbol_str.chars().any(is_in_ascii_confusable_closure_relevant_list) {
-                symbol_strs_and_spans.push((symbol_str, *sp));
+            has_non_ascii_idents = true;
+            cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
+                lint.build("identifier contains non-ASCII characters").emit()
+            });
+            if check_uncommon_codepoints
+                && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
+            {
+                cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
+                    lint.build("identifier contains uncommon Unicode codepoints").emit()
+                })
             }
         }
-        if !in_fast_path {
-            // slow path
-            for (symbol, sp) in symbols.iter() {
+
+        if has_non_ascii_idents && check_confusable_idents {
+            let mut skeleton_map: FxHashMap<CowBoxSymStr, (SymbolStr, Span, bool)> =
+                FxHashMap::with_capacity_and_hasher(symbols.len(), Default::default());
+            let mut str_buf = String::new();
+            for (symbol, &sp) in symbols.iter() {
+                fn calc_skeleton(symbol_str: &SymbolStr, buffer: &mut String) -> CowBoxSymStr {
+                    use std::mem::replace;
+                    use unicode_security::confusable_detection::skeleton;
+                    buffer.clear();
+                    buffer.extend(skeleton(symbol_str));
+                    if *symbol_str == *buffer {
+                        CowBoxSymStr::Interned(symbol_str.clone())
+                    } else {
+                        let owned = replace(buffer, String::new());
+                        CowBoxSymStr::Owned(owned.into_boxed_str())
+                    }
+                }
                 let symbol_str = symbol.as_str();
-                symbol_strs_and_spans.push((symbol_str, *sp));
+                let is_ascii = symbol_str.is_ascii();
+                let skeleton = calc_skeleton(&symbol_str, &mut str_buf);
+                skeleton_map
+                    .entry(skeleton)
+                    .and_modify(|(existing_symbolstr, existing_span, existing_is_ascii)| {
+                        if !*existing_is_ascii || !is_ascii {
+                            cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
+                                lint.build(&format!(
+                                    "identifier pair considered confusable between `{}` and `{}`",
+                                    existing_symbolstr, symbol_str
+                                ))
+                                .span_label(
+                                    *existing_span,
+                                    "this is where the previous identifier occurred",
+                                )
+                                .emit();
+                            });
+                        }
+                        if *existing_is_ascii && !is_ascii {
+                            *existing_symbolstr = symbol_str.clone();
+                            *existing_span = sp;
+                            *existing_is_ascii = is_ascii;
+                        }
+                    })
+                    .or_insert((symbol_str, sp, is_ascii));
             }
         }
-        drop(symbols);
-        symbol_strs_and_spans.sort_by_key(|x| x.0.clone());
-        let mut skeleton_map =
-            FxHashMap::with_capacity_and_hasher(symbol_strs_and_spans.len(), Default::default());
-        let mut str_buf = String::new();
-        for (symbol_str, sp) in symbol_strs_and_spans {
-            let skeleton = calc_skeleton(symbol_str.clone(), &mut str_buf);
-            skeleton_map
-                .entry(skeleton)
-                .and_modify(|(existing_symbolstr, existing_span)| {
-                    cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
-                        lint.build(&format!(
-                            "identifier pair considered confusable between `{}` and `{}`",
-                            existing_symbolstr, symbol_str
-                        ))
-                        .span_label(
-                            *existing_span,
-                            "this is where the previous identifier occurred",
-                        )
-                        .emit();
+
+        if has_non_ascii_idents && check_mixed_script_confusables {
+            use unicode_security::is_potential_mixed_script_confusable_char;
+            use unicode_security::mixed_script::AugmentedScriptSet;
+
+            #[derive(Clone)]
+            enum ScriptSetUsage {
+                Suspicious(Vec<char>, Span),
+                Verified,
+            }
+
+            let mut script_states: FxHashMap<AugmentedScriptSet, ScriptSetUsage> =
+                FxHashMap::default();
+            let latin_augmented_script_set = AugmentedScriptSet::for_char('A');
+            script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified);
+
+            let mut has_suspicous = false;
+            for (symbol, &sp) in symbols.iter() {
+                let symbol_str = symbol.as_str();
+                for ch in symbol_str.chars() {
+                    if ch.is_ascii() {
+                        // all ascii characters are covered by exception.
+                        continue;
+                    }
+                    if !GeneralSecurityProfile::identifier_allowed(ch) {
+                        // this character is covered by `uncommon_codepoints` lint.
+                        continue;
+                    }
+                    let augmented_script_set = AugmentedScriptSet::for_char(ch);
+                    script_states
+                        .entry(augmented_script_set)
+                        .and_modify(|existing_state| {
+                            if let ScriptSetUsage::Suspicious(ch_list, _) = existing_state {
+                                if is_potential_mixed_script_confusable_char(ch) {
+                                    ch_list.push(ch);
+                                } else {
+                                    *existing_state = ScriptSetUsage::Verified;
+                                }
+                            }
+                        })
+                        .or_insert_with(|| {
+                            if !is_potential_mixed_script_confusable_char(ch) {
+                                ScriptSetUsage::Verified
+                            } else {
+                                has_suspicous = true;
+                                ScriptSetUsage::Suspicious(vec![ch], sp)
+                            }
+                        });
+                }
+            }
+
+            if has_suspicous {
+                let verified_augmented_script_sets = script_states
+                    .iter()
+                    .flat_map(|(k, v)| match v {
+                        ScriptSetUsage::Verified => Some(*k),
+                        _ => None,
+                    })
+                    .collect::<Vec<_>>();
+
+                // we're sorting the output here.
+                let mut lint_reports: BTreeMap<(Span, Vec<char>), AugmentedScriptSet> =
+                    BTreeMap::new();
+
+                'outerloop: for (augment_script_set, usage) in script_states {
+                    let (mut ch_list, sp) = match usage {
+                        ScriptSetUsage::Verified => continue,
+                        ScriptSetUsage::Suspicious(ch_list, sp) => (ch_list, sp),
+                    };
+
+                    if augment_script_set.is_all() {
+                        continue;
+                    }
+
+                    for existing in verified_augmented_script_sets.iter() {
+                        if existing.is_all() {
+                            continue;
+                        }
+                        let mut intersect = *existing;
+                        intersect.intersect_with(augment_script_set);
+                        if !intersect.is_empty() && !intersect.is_all() {
+                            continue 'outerloop;
+                        }
+                    }
+
+                    ch_list.sort();
+                    ch_list.dedup();
+                    lint_reports.insert((sp, ch_list), augment_script_set);
+                }
+
+                for ((sp, ch_list), script_set) in lint_reports {
+                    cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
+                        let message = format!(
+                            "The usage of Script Group `{}` in this crate consists solely of mixed script confusables",
+                            script_set);
+                        let mut note = "The usage includes ".to_string();
+                        for (idx, ch) in ch_list.into_iter().enumerate() {
+                            if idx != 0 {
+                                note += ", ";
+                            }
+                            let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
+                            note += &char_info;
+                        }
+                        note += ".";
+                        lint.build(&message).note(&note).note("Please recheck to make sure their usages are indeed what you want.").emit()
                     });
-                })
-                .or_insert((symbol_str, sp));
+                }
+            }
         }
     }
-    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
-        use unicode_security::GeneralSecurityProfile;
-        let name_str = ident.name.as_str();
-        if name_str.is_ascii() {
-            return;
+}
+
+mod utils {
+    use rustc_span::symbol::SymbolStr;
+    use std::hash::{Hash, Hasher};
+    use std::ops::Deref;
+
+    pub(super) enum CowBoxSymStr {
+        Interned(SymbolStr),
+        Owned(Box<str>),
+    }
+
+    impl Deref for CowBoxSymStr {
+        type Target = str;
+
+        fn deref(&self) -> &str {
+            match self {
+                CowBoxSymStr::Interned(interned) => interned,
+                CowBoxSymStr::Owned(ref owned) => owned,
+            }
+        }
+    }
+
+    impl Hash for CowBoxSymStr {
+        #[inline]
+        fn hash<H: Hasher>(&self, state: &mut H) {
+            Hash::hash(&**self, state)
         }
-        cx.struct_span_lint(NON_ASCII_IDENTS, ident.span, |lint| {
-            lint.build("identifier contains non-ASCII characters").emit()
-        });
-        if !name_str.chars().all(GeneralSecurityProfile::identifier_allowed) {
-            cx.struct_span_lint(UNCOMMON_CODEPOINTS, ident.span, |lint| {
-                lint.build("identifier contains uncommon Unicode codepoints").emit()
-            })
+    }
+
+    impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
+        #[inline]
+        fn eq(&self, other: &CowBoxSymStr) -> bool {
+            PartialEq::eq(&**self, &**other)
         }
     }
+
+    impl Eq for CowBoxSymStr {}
 }
index a19c9a3557996d68153a8ac522bdc4534b0ba111..cfafb86fbedb1e0574ecd80c83668b48a768133c 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
 use rustc_target::spec::abi::Abi;
 
@@ -498,10 +498,24 @@ fn is_comparison(binop: hir::BinOp) -> bool {
     "proper use of libc types in foreign modules"
 }
 
-declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]);
+declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
+
+declare_lint! {
+    IMPROPER_CTYPES_DEFINITIONS,
+    Warn,
+    "proper use of libc types in foreign item definitions"
+}
+
+declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
+
+enum ImproperCTypesMode {
+    Declarations,
+    Definitions,
+}
 
 struct ImproperCTypesVisitor<'a, 'tcx> {
     cx: &'a LateContext<'a, 'tcx>,
+    mode: ImproperCTypesMode,
 }
 
 enum FfiResult<'tcx> {
@@ -804,6 +818,15 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                 help: Some("consider using a struct instead".into()),
             },
 
+            ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
+                if {
+                    matches!(self.mode, ImproperCTypesMode::Definitions)
+                        && ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env)
+                } =>
+            {
+                FfiSafe
+            }
+
             ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
                 self.check_type_for_ffi(cache, ty)
             }
@@ -811,20 +834,16 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
             ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
 
             ty::FnPtr(sig) => {
-                match sig.abi() {
-                    Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
-                        return FfiUnsafe {
-                            ty,
-                            reason: "this function pointer has Rust-specific calling convention"
+                if self.is_internal_abi(sig.abi()) {
+                    return FfiUnsafe {
+                        ty,
+                        reason: "this function pointer has Rust-specific calling convention".into(),
+                        help: Some(
+                            "consider using an `extern fn(...) -> ...` \
+                                    function pointer instead"
                                 .into(),
-                            help: Some(
-                                "consider using an `extern fn(...) -> ...` \
-                                        function pointer instead"
-                                    .into(),
-                            ),
-                        };
-                    }
-                    _ => {}
+                        ),
+                    };
                 }
 
                 let sig = cx.erase_late_bound_regions(&sig);
@@ -857,7 +876,16 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                 FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
             }
 
+            // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
+            //  so they are currently ignored for the purposes of this lint.
+            ty::Param(..) | ty::Projection(..)
+                if matches!(self.mode, ImproperCTypesMode::Definitions) =>
+            {
+                FfiSafe
+            }
+
             ty::Param(..)
+            | ty::Projection(..)
             | ty::Infer(..)
             | ty::Bound(..)
             | ty::Error(_)
@@ -865,7 +893,6 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
             | ty::Placeholder(..)
-            | ty::Projection(..)
             | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
         }
     }
@@ -877,9 +904,20 @@ fn emit_ffi_unsafe_type_lint(
         note: &str,
         help: Option<&str>,
     ) {
-        self.cx.struct_span_lint(IMPROPER_CTYPES, sp, |lint| {
-            let mut diag =
-                lint.build(&format!("`extern` block uses type `{}`, which is not FFI-safe", ty));
+        let lint = match self.mode {
+            ImproperCTypesMode::Declarations => IMPROPER_CTYPES,
+            ImproperCTypesMode::Definitions => IMPROPER_CTYPES_DEFINITIONS,
+        };
+
+        self.cx.struct_span_lint(lint, sp, |lint| {
+            let item_description = match self.mode {
+                ImproperCTypesMode::Declarations => "block",
+                ImproperCTypesMode::Definitions => "fn",
+            };
+            let mut diag = lint.build(&format!(
+                "`extern` {} uses type `{}`, which is not FFI-safe",
+                item_description, ty
+            ));
             diag.span_label(sp, "not FFI-safe");
             if let Some(help) = help {
                 diag.help(help);
@@ -947,7 +985,7 @@ fn check_type_for_ffi_and_report_errors(
 
         // it is only OK to use this function because extern fns cannot have
         // any generic types right now:
-        let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+        let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
 
         // C doesn't really support passing arrays by value - the only way to pass an array by value
         // is through a struct. So, first test that the top level isn't an array, and then
@@ -997,15 +1035,22 @@ fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
         let ty = self.cx.tcx.type_of(def_id);
         self.check_type_for_ffi_and_report_errors(span, ty, true, false);
     }
+
+    fn is_internal_abi(&self, abi: Abi) -> bool {
+        if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
+            true
+        } else {
+            false
+        }
+    }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDeclarations {
     fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem<'_>) {
-        let mut vis = ImproperCTypesVisitor { cx };
+        let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Declarations };
         let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
-        if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
-            // Don't worry about types in internal ABIs.
-        } else {
+
+        if !vis.is_internal_abi(abi) {
             match it.kind {
                 hir::ForeignItemKind::Fn(ref decl, _, _) => {
                     vis.check_foreign_fn(it.hir_id, decl);
@@ -1019,6 +1064,31 @@ fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem
     }
 }
 
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDefinitions {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        kind: hir::intravisit::FnKind<'tcx>,
+        decl: &'tcx hir::FnDecl<'_>,
+        _: &'tcx hir::Body<'_>,
+        _: Span,
+        hir_id: hir::HirId,
+    ) {
+        use hir::intravisit::FnKind;
+
+        let abi = match kind {
+            FnKind::ItemFn(_, _, header, ..) => header.abi,
+            FnKind::Method(_, sig, ..) => sig.header.abi,
+            _ => return,
+        };
+
+        let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Definitions };
+        if !vis.is_internal_abi(abi) {
+            vis.check_foreign_fn(hir_id, decl);
+        }
+    }
+}
+
 declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
index 79e1a6cc5dcdb7e3cb3024948bad3541bdbb6b9d..f54ed9b92029ecbb0e34f511356432e9c05f91aa 100644 (file)
@@ -15,6 +15,7 @@ pub struct RustString {
 
 /// Appending to a Rust string -- used by RawRustStringOstream.
 #[no_mangle]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
 pub unsafe extern "C" fn LLVMRustStringWriteImpl(
     sr: &RustString,
     ptr: *const c_char,
index 0dc007bbfd72f8db4fa5acdea855178381a6cd7d..2c80c846681a66e60eba35f04fca53d0e5f40289 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_expand::base::SyntaxExtension;
-use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
 use rustc_middle::middle::cstore::DepKind;
@@ -896,6 +896,7 @@ pub fn process_extern_crate(
         &mut self,
         item: &ast::Item,
         definitions: &Definitions,
+        def_id: LocalDefId,
     ) -> CrateNum {
         match item.kind {
             ast::ItemKind::ExternCrate(orig_name) => {
@@ -918,7 +919,6 @@ pub fn process_extern_crate(
 
                 let cnum = self.resolve_crate(name, item.span, dep_kind, None);
 
-                let def_id = definitions.opt_local_def_id(item.id).unwrap();
                 let path_len = definitions.def_path(def_id).data.len();
                 self.update_extern_crate(
                     cnum,
index 5a4862d4521833f38c12ead3abf493d8ca4c770b..1bdac1039b55a48e07bb179599993968857b0fdf 100644 (file)
@@ -488,6 +488,8 @@ impl<'a> CrateLocator<'a> {
                 && self.triple != TargetTriple::from_triple(config::host_triple())
             {
                 err.note(&format!("the `{}` target may not be installed", self.triple));
+            } else if self.crate_name == sym::profiler_builtins {
+                err.note(&"the compiler may have been built without the profiler runtime");
             }
             err.span_label(self.span, "can't find crate");
             err
index d1cfc4867a2fe0f5c57007177e17cbc8b21ccb7f..3a4fc581f5f2607d91e1a34c5b199bdfc8532eb6 100644 (file)
@@ -56,7 +56,7 @@ fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> {
     }
 }
 
-fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
+pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
     match node {
         Node::Item(Item {
             kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
index 69b4adb3a0e1d7ed2e5b1f8f7ea5d2b843d32401..f5b0b73c49de1cf7230f100bfd2e3d53a377d7c5 100644 (file)
@@ -67,13 +67,15 @@ impl<'a> StableHashingContext<'a> {
     /// Don't use it for anything else or you'll run the risk of
     /// leaking data out of the tracking system.
     #[inline]
-    pub fn new(
+    fn new_with_or_without_spans(
         sess: &'a Session,
         krate: &'a hir::Crate<'a>,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
+        always_ignore_spans: bool,
     ) -> Self {
-        let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
+        let hash_spans_initial =
+            !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
 
         StableHashingContext {
             sess,
@@ -88,6 +90,33 @@ pub fn new(
         }
     }
 
+    #[inline]
+    pub fn new(
+        sess: &'a Session,
+        krate: &'a hir::Crate<'a>,
+        definitions: &'a Definitions,
+        cstore: &'a dyn CrateStore,
+    ) -> Self {
+        Self::new_with_or_without_spans(
+            sess,
+            krate,
+            definitions,
+            cstore,
+            /*always_ignore_spans=*/ false,
+        )
+    }
+
+    #[inline]
+    pub fn ignore_spans(
+        sess: &'a Session,
+        krate: &'a hir::Crate<'a>,
+        definitions: &'a Definitions,
+        cstore: &'a dyn CrateStore,
+    ) -> Self {
+        let always_ignore_spans = true;
+        Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
+    }
+
     #[inline]
     pub fn sess(&self) -> &'a Session {
         self.sess
index 649766547990f264bf5b81fbcdd0705e383bebc6..d89c35d313ca3c41d0c15d84867d167906b778fc 100644 (file)
@@ -164,8 +164,8 @@ pub struct Body<'tcx> {
     /// The user may be writing e.g. `&[(SOME_CELL, 42)][i].1` and this would get promoted, because
     /// we'd statically know that no thing with interior mutability will ever be available to the
     /// user without some serious unsafe code.  Now this means that our promoted is actually
-    /// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because the
-    /// index may be a runtime value. Such a promoted value is illegal because it has reachable
+    /// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because
+    /// the index may be a runtime value. Such a promoted value is illegal because it has reachable
     /// interior mutability. This flag just makes this situation very obvious where the previous
     /// implementation without the flag hid this situation silently.
     /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
@@ -2921,3 +2921,18 @@ pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) ->
         }
     }
 }
+
+/// Coverage data associated with each function (MIR) instrumented with coverage counters, when
+/// compiled with `-Zinstrument_coverage`. The query `tcx.coverage_data(DefId)` computes these
+/// values on demand (during code generation). This query is only valid after executing the MIR pass
+/// `InstrumentCoverage`.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub struct CoverageData {
+    /// A hash value that can be used by the consumer of the coverage profile data to detect
+    /// changes to the instrumented source of the associated MIR body (typically, for an
+    /// individual function).
+    pub hash: u64,
+
+    /// The total number of coverage region counters added to the MIR `Body`.
+    pub num_counters: u32,
+}
index 9fd45ddf6e60ea0cbbe950bf6be70d1897c8a633..2f51b98085b4eea4d1b1f7395c8484b1f34e2834 100644 (file)
@@ -231,6 +231,12 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
             cache_on_disk_if { key.is_local() }
         }
 
+        query coverage_data(key: DefId) -> mir::CoverageData {
+            desc { |tcx| "retrieving coverage data from MIR for `{}`", tcx.def_path_str(key) }
+            storage(ArenaCacheSelector<'tcx>)
+            cache_on_disk_if { key.is_local() }
+        }
+
         query promoted_mir(key: DefId) -> IndexVec<mir::Promoted, mir::Body<'tcx>> {
             desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
             storage(ArenaCacheSelector<'tcx>)
index fb9565e4b9825e352be48f4116baa1ddb3421c5f..df08e083d2cbb98ebbeab0e60a3dc73be98cface 100644 (file)
@@ -1307,6 +1307,13 @@ pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
         StableHashingContext::new(self.sess, krate, self.definitions, &*self.cstore)
     }
 
+    #[inline(always)]
+    pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
+        let krate = self.gcx.untracked_crate;
+
+        StableHashingContext::ignore_spans(self.sess, krate, self.definitions, &*self.cstore)
+    }
+
     // This method makes sure that we have a DepNode and a Fingerprint for
     // every upstream crate. It needs to be called once right after the tcx is
     // created.
index e51d9ba9c021ded81b5bc038034302922eff8571..f9b3c319c1f66654463ee89ff3c6386007f9325c 100644 (file)
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
-use rustc_errors::ErrorReported;
+use rustc_errors::{ErrorReported, FatalError};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_session::config::EntryFnType;
+use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
 use smallvec::SmallVec;
 use std::iter;
 
@@ -294,7 +295,13 @@ pub fn collect_crate_mono_items(
         tcx.sess.time("monomorphization_collector_graph_walk", || {
             par_iter(roots).for_each(|root| {
                 let mut recursion_depths = DefIdMap::default();
-                collect_items_rec(tcx, root, visited, &mut recursion_depths, inlining_map);
+                collect_items_rec(
+                    tcx,
+                    dummy_spanned(root),
+                    visited,
+                    &mut recursion_depths,
+                    inlining_map,
+                );
             });
         });
     }
@@ -323,29 +330,30 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
     // We can only codegen items that are instantiable - items all of
     // whose predicates hold. Luckily, items that aren't instantiable
     // can't actually be used, so we can just skip codegenning them.
-    roots.retain(|root| root.is_instantiable(tcx));
-
     roots
+        .into_iter()
+        .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node))
+        .collect()
 }
 
 // Collect all monomorphized items reachable from `starting_point`
 fn collect_items_rec<'tcx>(
     tcx: TyCtxt<'tcx>,
-    starting_point: MonoItem<'tcx>,
+    starting_point: Spanned<MonoItem<'tcx>>,
     visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
     recursion_depths: &mut DefIdMap<usize>,
     inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
 ) {
-    if !visited.lock_mut().insert(starting_point) {
+    if !visited.lock_mut().insert(starting_point.node) {
         // We've been here already, no need to search again.
         return;
     }
-    debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx, true));
+    debug!("BEGIN collect_items_rec({})", starting_point.node.to_string(tcx, true));
 
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
 
-    match starting_point {
+    match starting_point.node {
         MonoItem::Static(def_id) => {
             let instance = Instance::mono(tcx, def_id);
 
@@ -353,7 +361,7 @@ fn collect_items_rec<'tcx>(
             debug_assert!(should_monomorphize_locally(tcx, &instance));
 
             let ty = instance.monomorphic_ty(tcx);
-            visit_drop_use(tcx, ty, true, &mut neighbors);
+            visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors);
 
             recursion_depth_reset = None;
 
@@ -366,7 +374,8 @@ fn collect_items_rec<'tcx>(
             debug_assert!(should_monomorphize_locally(tcx, &instance));
 
             // Keep track of the monomorphization recursion depth
-            recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths));
+            recursion_depth_reset =
+                Some(check_recursion_limit(tcx, instance, starting_point.span, recursion_depths));
             check_type_length_limit(tcx, instance);
 
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
@@ -378,7 +387,7 @@ fn collect_items_rec<'tcx>(
         }
     }
 
-    record_accesses(tcx, starting_point, &neighbors[..], inlining_map);
+    record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
 
     for neighbour in neighbors {
         collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map);
@@ -388,13 +397,13 @@ fn collect_items_rec<'tcx>(
         recursion_depths.insert(def_id, depth);
     }
 
-    debug!("END collect_items_rec({})", starting_point.to_string(tcx, true));
+    debug!("END collect_items_rec({})", starting_point.node.to_string(tcx, true));
 }
 
-fn record_accesses<'tcx>(
+fn record_accesses<'a, 'tcx: 'a>(
     tcx: TyCtxt<'tcx>,
     caller: MonoItem<'tcx>,
-    callees: &[MonoItem<'tcx>],
+    callees: impl Iterator<Item = &'a MonoItem<'tcx>>,
     inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
 ) {
     let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| {
@@ -405,7 +414,7 @@ fn record_accesses<'tcx>(
     // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec`
     // instead to avoid creating this `SmallVec`.
     let accesses: SmallVec<[_; 128]> =
-        callees.iter().map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
+        callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
 
     inlining_map.lock_mut().record_accesses(caller, &accesses);
 }
@@ -413,6 +422,7 @@ fn record_accesses<'tcx>(
 fn check_recursion_limit<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
+    span: Span,
     recursion_depths: &mut DefIdMap<usize>,
 ) -> (DefId, usize) {
     let def_id = instance.def_id();
@@ -432,12 +442,13 @@ fn check_recursion_limit<'tcx>(
     // infinite expansion.
     if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
         let error = format!("reached the recursion limit while instantiating `{}`", instance);
-        if let Some(def_id) = def_id.as_local() {
-            let hir_id = tcx.hir().as_local_hir_id(def_id);
-            tcx.sess.span_fatal(tcx.hir().span(hir_id), &error);
-        } else {
-            tcx.sess.fatal(&error);
-        }
+        let mut err = tcx.sess.struct_span_fatal(span, &error);
+        err.span_note(
+            tcx.def_span(def_id),
+            &format!("`{}` defined here", tcx.def_path_str(def_id)),
+        );
+        err.emit();
+        FatalError.raise();
     }
 
     recursion_depths.insert(def_id, recursion_depth + 1);
@@ -498,7 +509,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
 struct MirNeighborCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
-    output: &'a mut Vec<MonoItem<'tcx>>,
+    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
     instance: Instance<'tcx>,
 }
 
@@ -520,6 +531,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
         debug!("visiting rvalue {:?}", *rvalue);
 
+        let span = self.body.source_info(location).span;
+
         match *rvalue {
             // When doing an cast from a regular pointer to a fat pointer, we
             // have to instantiate all methods of the trait being cast to, so we
@@ -542,6 +555,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                         self.tcx,
                         target_ty,
                         source_ty,
+                        span,
                         self.output,
                     );
                 }
@@ -553,7 +567,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
             ) => {
                 let fn_ty = operand.ty(self.body, self.tcx);
                 let fn_ty = self.monomorphize(fn_ty);
-                visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+                visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output);
             }
             mir::Rvalue::Cast(
                 mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
@@ -571,7 +585,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                             ty::ClosureKind::FnOnce,
                         );
                         if should_monomorphize_locally(self.tcx, &instance) {
-                            self.output.push(create_fn_mono_item(instance));
+                            self.output.push(create_fn_mono_item(instance, span));
                         }
                     }
                     _ => bug!(),
@@ -583,7 +597,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                     tcx.require_lang_item(ExchangeMallocFnLangItem, None);
                 let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
                 if should_monomorphize_locally(tcx, &instance) {
-                    self.output.push(create_fn_mono_item(instance));
+                    self.output.push(create_fn_mono_item(instance, span));
                 }
             }
             mir::Rvalue::ThreadLocalRef(def_id) => {
@@ -591,7 +605,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                 let instance = Instance::mono(self.tcx, def_id);
                 if should_monomorphize_locally(self.tcx, &instance) {
                     trace!("collecting thread-local static {:?}", def_id);
-                    self.output.push(MonoItem::Static(def_id));
+                    self.output.push(respan(span, MonoItem::Static(def_id)));
                 }
             }
             _ => { /* not interesting */ }
@@ -626,32 +640,33 @@ fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location)
 
     fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
         debug!("visiting terminator {:?} @ {:?}", terminator, location);
+        let source = self.body.source_info(location).span;
 
         let tcx = self.tcx;
         match terminator.kind {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.body, tcx);
                 let callee_ty = self.monomorphize(callee_ty);
-                visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
+                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output);
             }
             mir::TerminatorKind::Drop { ref place, .. }
             | mir::TerminatorKind::DropAndReplace { ref place, .. } => {
                 let ty = place.ty(self.body, self.tcx).ty;
                 let ty = self.monomorphize(ty);
-                visit_drop_use(self.tcx, ty, true, self.output);
+                visit_drop_use(self.tcx, ty, true, source, self.output);
             }
             mir::TerminatorKind::InlineAsm { ref operands, .. } => {
                 for op in operands {
                     match *op {
                         mir::InlineAsmOperand::SymFn { ref value } => {
                             let fn_ty = self.monomorphize(value.literal.ty);
-                            visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+                            visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output);
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
                             if should_monomorphize_locally(self.tcx, &instance) {
                                 trace!("collecting asm sym static {:?}", def_id);
-                                self.output.push(MonoItem::Static(def_id));
+                                self.output.push(respan(source, MonoItem::Static(def_id)));
                             }
                         }
                         _ => {}
@@ -687,17 +702,19 @@ fn visit_drop_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     let instance = Instance::resolve_drop_in_place(tcx, ty);
-    visit_instance_use(tcx, instance, is_direct_call, output);
+    visit_instance_use(tcx, instance, is_direct_call, source, output);
 }
 
 fn visit_fn_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     if let ty::FnDef(def_id, substs) = ty.kind {
         let instance = if is_direct_call {
@@ -706,7 +723,7 @@ fn visit_fn_use<'tcx>(
             ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs)
                 .unwrap()
         };
-        visit_instance_use(tcx, instance, is_direct_call, output);
+        visit_instance_use(tcx, instance, is_direct_call, source, output);
     }
 }
 
@@ -714,7 +731,8 @@ fn visit_instance_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::Instance<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
     if !should_monomorphize_locally(tcx, &instance) {
@@ -730,7 +748,7 @@ fn visit_instance_use<'tcx>(
         ty::InstanceDef::DropGlue(_, None) => {
             // Don't need to emit noop drop glue if we are calling directly.
             if !is_direct_call {
-                output.push(create_fn_mono_item(instance));
+                output.push(create_fn_mono_item(instance, source));
             }
         }
         ty::InstanceDef::DropGlue(_, Some(_))
@@ -740,7 +758,7 @@ fn visit_instance_use<'tcx>(
         | ty::InstanceDef::Item(..)
         | ty::InstanceDef::FnPtrShim(..)
         | ty::InstanceDef::CloneShim(..) => {
-            output.push(create_fn_mono_item(instance));
+            output.push(create_fn_mono_item(instance, source));
         }
     }
 }
@@ -832,7 +850,6 @@ fn find_vtable_types_for_unsizing<'tcx>(
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
         let param_env = ty::ParamEnv::reveal_all();
         let type_has_metadata = |ty: Ty<'tcx>| -> bool {
-            use rustc_span::DUMMY_SP;
             if ty.is_sized(tcx.at(DUMMY_SP), param_env) {
                 return false;
             }
@@ -886,9 +903,9 @@ fn find_vtable_types_for_unsizing<'tcx>(
     }
 }
 
-fn create_fn_mono_item(instance: Instance<'_>) -> MonoItem<'_> {
+fn create_fn_mono_item(instance: Instance<'_>, source: Span) -> Spanned<MonoItem<'_>> {
     debug!("create_fn_mono_item(instance={})", instance);
-    MonoItem::Fn(instance)
+    respan(source, MonoItem::Fn(instance))
 }
 
 /// Creates a `MonoItem` for each method that is referenced by the vtable for
@@ -897,7 +914,8 @@ fn create_mono_items_for_vtable_methods<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ty: Ty<'tcx>,
     impl_ty: Ty<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     assert!(
         !trait_ty.needs_subst()
@@ -927,12 +945,12 @@ fn create_mono_items_for_vtable_methods<'tcx>(
                     .unwrap()
                 })
                 .filter(|&instance| should_monomorphize_locally(tcx, &instance))
-                .map(create_fn_mono_item);
+                .map(|item| create_fn_mono_item(item, source));
             output.extend(methods);
         }
 
         // Also add the destructor.
-        visit_drop_use(tcx, impl_ty, false, output);
+        visit_drop_use(tcx, impl_ty, false, source, output);
     }
 }
 
@@ -943,7 +961,7 @@ fn create_mono_items_for_vtable_methods<'tcx>(
 struct RootCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     mode: MonoItemCollectionMode,
-    output: &'a mut Vec<MonoItem<'tcx>>,
+    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
     entry_fn: Option<(LocalDefId, EntryFnType)>,
 }
 
@@ -980,7 +998,7 @@ fn visit_item(&mut self, item: &'v hir::Item<'v>) {
 
                         let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty())
                             .monomorphic_ty(self.tcx);
-                        visit_drop_use(self.tcx, ty, true, self.output);
+                        visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
                     }
                 }
             }
@@ -989,12 +1007,12 @@ fn visit_item(&mut self, item: &'v hir::Item<'v>) {
                     "RootCollector: ItemKind::GlobalAsm({})",
                     def_id_to_string(self.tcx, self.tcx.hir().local_def_id(item.hir_id))
                 );
-                self.output.push(MonoItem::GlobalAsm(item.hir_id));
+                self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id)));
             }
             hir::ItemKind::Static(..) => {
                 let def_id = self.tcx.hir().local_def_id(item.hir_id);
                 debug!("RootCollector: ItemKind::Static({})", def_id_to_string(self.tcx, def_id));
-                self.output.push(MonoItem::Static(def_id.to_def_id()));
+                self.output.push(dummy_spanned(MonoItem::Static(def_id.to_def_id())));
             }
             hir::ItemKind::Const(..) => {
                 // const items only generate mono items if they are
@@ -1051,7 +1069,7 @@ fn push_if_root(&mut self, def_id: LocalDefId) {
             debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
 
             let instance = Instance::mono(self.tcx, def_id.to_def_id());
-            self.output.push(create_fn_mono_item(instance));
+            self.output.push(create_fn_mono_item(instance, DUMMY_SP));
         }
     }
 
@@ -1088,7 +1106,7 @@ fn push_extra_entry_roots(&mut self) {
         .unwrap()
         .unwrap();
 
-        self.output.push(create_fn_mono_item(start_instance));
+        self.output.push(create_fn_mono_item(start_instance, DUMMY_SP));
     }
 }
 
@@ -1100,7 +1118,7 @@ fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 fn create_mono_items_for_default_impls<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &'tcx hir::Item<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     match item.kind {
         hir::ItemKind::Impl { ref generics, ref items, .. } => {
@@ -1145,8 +1163,9 @@ fn create_mono_items_for_default_impls<'tcx>(
                         .unwrap()
                         .unwrap();
 
-                    let mono_item = create_fn_mono_item(instance);
-                    if mono_item.is_instantiable(tcx) && should_monomorphize_locally(tcx, &instance)
+                    let mono_item = create_fn_mono_item(instance, DUMMY_SP);
+                    if mono_item.node.is_instantiable(tcx)
+                        && should_monomorphize_locally(tcx, &instance)
                     {
                         output.push(mono_item);
                     }
@@ -1158,14 +1177,18 @@ fn create_mono_items_for_default_impls<'tcx>(
 }
 
 /// Scans the miri alloc in order to find function calls, closures, and drop-glue.
-fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<MonoItem<'tcx>>) {
+fn collect_miri<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    alloc_id: AllocId,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+) {
     match tcx.global_alloc(alloc_id) {
         GlobalAlloc::Static(def_id) => {
             assert!(!tcx.is_thread_local_static(def_id));
             let instance = Instance::mono(tcx, def_id);
             if should_monomorphize_locally(tcx, &instance) {
                 trace!("collecting static {:?}", def_id);
-                output.push(MonoItem::Static(def_id));
+                output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
         }
         GlobalAlloc::Memory(alloc) => {
@@ -1179,7 +1202,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon
         GlobalAlloc::Function(fn_instance) => {
             if should_monomorphize_locally(tcx, &fn_instance) {
                 trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
-                output.push(create_fn_mono_item(fn_instance));
+                output.push(create_fn_mono_item(fn_instance, DUMMY_SP));
             }
         }
     }
@@ -1189,7 +1212,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon
 fn collect_neighbours<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     debug!("collect_neighbours: {:?}", instance.def_id());
     let body = tcx.instance_mir(instance.def);
@@ -1207,7 +1230,7 @@ fn def_id_to_string(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
 fn collect_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     value: ConstValue<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     match value {
         ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output),
index 2806d1c8949fea4fa7b27c20d941f09dd8d05b0c..eb614170baae5b943ea781159d052d4341388b85 100644 (file)
@@ -574,8 +574,16 @@ fn const_prop(
             }
 
             // Do not try creating references (#67862)
-            Rvalue::Ref(_, _, place_ref) => {
-                trace!("skipping Ref({:?})", place_ref);
+            Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
+                trace!("skipping AddressOf | Ref for {:?}", place);
+
+                // This may be creating mutable references or immutable references to cells.
+                // If that happens, the pointed to value could be mutated via that reference.
+                // Since we aren't tracking references, the const propagator loses track of what
+                // value the local has right now.
+                // Thus, all locals that have their reference taken
+                // must not take part in propagation.
+                Self::remove_const(&mut self.ecx, place.local);
 
                 return None;
             }
@@ -715,6 +723,9 @@ enum ConstPropMode {
     OnlyInsideOwnBlock,
     /// The `Local` can be propagated into but reads cannot be propagated.
     OnlyPropagateInto,
+    /// The `Local` cannot be part of propagation at all. Any statement
+    /// referencing it either for reading or writing will not get propagated.
+    NoPropagation,
 }
 
 struct CanConstProp {
@@ -780,7 +791,9 @@ fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
                         // end of the block anyway, and inside the block we overwrite previous
                         // states as applicable.
                         ConstPropMode::OnlyInsideOwnBlock => {}
-                        other => {
+                        ConstPropMode::NoPropagation => {}
+                        ConstPropMode::OnlyPropagateInto => {}
+                        other @ ConstPropMode::FullConstProp => {
                             trace!(
                                 "local {:?} can't be propagated because of multiple assignments",
                                 local,
@@ -812,7 +825,7 @@ fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
             | MutatingUse(MutatingUseContext::Borrow)
             | MutatingUse(MutatingUseContext::AddressOf) => {
                 trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
-                self.can_const_prop[local] = ConstPropMode::OnlyPropagateInto;
+                self.can_const_prop[local] = ConstPropMode::NoPropagation;
             }
         }
     }
@@ -857,19 +870,22 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
                             }
                         }
                     }
-                    if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
-                        trace!(
-                            "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
-                            place.local
-                        );
-                        self.locals_of_current_block.insert(place.local);
-                    }
-
-                    if can_const_prop == ConstPropMode::OnlyPropagateInto {
-                        trace!("can't propagate into {:?}", place);
-                        if place.local != RETURN_PLACE {
-                            Self::remove_const(&mut self.ecx, place.local);
+                    match can_const_prop {
+                        ConstPropMode::OnlyInsideOwnBlock => {
+                            trace!(
+                                "found local restricted to its block. \
+                                Will remove it from const-prop after block is finished. Local: {:?}",
+                                place.local
+                            );
+                            self.locals_of_current_block.insert(place.local);
                         }
+                        ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
+                            trace!("can't propagate into {:?}", place);
+                            if place.local != RETURN_PLACE {
+                                Self::remove_const(&mut self.ecx, place.local);
+                            }
+                        }
+                        ConstPropMode::FullConstProp => {}
                     }
                 } else {
                     // Const prop failed, so erase the destination, ensuring that whatever happens
@@ -889,6 +905,12 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
                     );
                     Self::remove_const(&mut self.ecx, place.local);
                 }
+            } else {
+                trace!(
+                    "cannot propagate into {:?}, because the type of the local is generic.",
+                    place,
+                );
+                Self::remove_const(&mut self.ecx, place.local);
             }
         } else {
             match statement.kind {
index c8702eeae1d5b15ebb1bcfc632cd2d2f36d7aa88..59be8dc224dee57d4d1e959160ff80646e23cf6f 100644 (file)
@@ -64,7 +64,7 @@
 use rustc_hir::lang_items::{GeneratorStateLangItem, PinTypeLangItem};
 use rustc_index::bit_set::{BitMatrix, BitSet};
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::GeneratorSubsts;
@@ -72,7 +72,7 @@
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::PanicStrategy;
 use std::borrow::Cow;
-use std::iter;
+use std::{iter, ops};
 
 pub struct StateTransform;
 
@@ -417,11 +417,7 @@ fn replace_local<'tcx>(
 
 struct LivenessInfo {
     /// Which locals are live across any suspension point.
-    ///
-    /// GeneratorSavedLocal is indexed in terms of the elements in this set;
-    /// i.e. GeneratorSavedLocal::new(1) corresponds to the second local
-    /// included in this set.
-    live_locals: BitSet<Local>,
+    saved_locals: GeneratorSavedLocals,
 
     /// The set of saved locals live at each suspension point.
     live_locals_at_suspension_points: Vec<BitSet<GeneratorSavedLocal>>,
@@ -524,49 +520,75 @@ fn locals_live_across_suspend_points(
             live_locals_at_suspension_points.push(live_locals);
         }
     }
+
     debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point);
+    let saved_locals = GeneratorSavedLocals(live_locals_at_any_suspension_point);
 
     // Renumber our liveness_map bitsets to include only the locals we are
     // saving.
     let live_locals_at_suspension_points = live_locals_at_suspension_points
         .iter()
-        .map(|live_here| renumber_bitset(&live_here, &live_locals_at_any_suspension_point))
+        .map(|live_here| saved_locals.renumber_bitset(&live_here))
         .collect();
 
     let storage_conflicts = compute_storage_conflicts(
         body_ref,
-        &live_locals_at_any_suspension_point,
+        &saved_locals,
         always_live_locals.clone(),
         requires_storage_results,
     );
 
     LivenessInfo {
-        live_locals: live_locals_at_any_suspension_point,
+        saved_locals,
         live_locals_at_suspension_points,
         storage_conflicts,
         storage_liveness: storage_liveness_map,
     }
 }
 
-/// Renumbers the items present in `stored_locals` and applies the renumbering
-/// to 'input`.
+/// The set of `Local`s that must be saved across yield points.
 ///
-/// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to
-/// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
-fn renumber_bitset(
-    input: &BitSet<Local>,
-    stored_locals: &BitSet<Local>,
-) -> BitSet<GeneratorSavedLocal> {
-    assert!(stored_locals.superset(&input), "{:?} not a superset of {:?}", stored_locals, input);
-    let mut out = BitSet::new_empty(stored_locals.count());
-    for (idx, local) in stored_locals.iter().enumerate() {
-        let saved_local = GeneratorSavedLocal::from(idx);
-        if input.contains(local) {
-            out.insert(saved_local);
+/// `GeneratorSavedLocal` is indexed in terms of the elements in this set;
+/// i.e. `GeneratorSavedLocal::new(1)` corresponds to the second local
+/// included in this set.
+struct GeneratorSavedLocals(BitSet<Local>);
+
+impl GeneratorSavedLocals {
+    /// Returns an iterator over each `GeneratorSavedLocal` along with the `Local` it corresponds
+    /// to.
+    fn iter_enumerated(&self) -> impl '_ + Iterator<Item = (GeneratorSavedLocal, Local)> {
+        self.iter().enumerate().map(|(i, l)| (GeneratorSavedLocal::from(i), l))
+    }
+
+    /// Transforms a `BitSet<Local>` that contains only locals saved across yield points to the
+    /// equivalent `BitSet<GeneratorSavedLocal>`.
+    fn renumber_bitset(&self, input: &BitSet<Local>) -> BitSet<GeneratorSavedLocal> {
+        assert!(self.superset(&input), "{:?} not a superset of {:?}", self.0, input);
+        let mut out = BitSet::new_empty(self.count());
+        for (saved_local, local) in self.iter_enumerated() {
+            if input.contains(local) {
+                out.insert(saved_local);
+            }
         }
+        out
+    }
+
+    fn get(&self, local: Local) -> Option<GeneratorSavedLocal> {
+        if !self.contains(local) {
+            return None;
+        }
+
+        let idx = self.iter().take_while(|&l| l < local).count();
+        Some(GeneratorSavedLocal::new(idx))
+    }
+}
+
+impl ops::Deref for GeneratorSavedLocals {
+    type Target = BitSet<Local>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
     }
-    debug!("renumber_bitset({:?}, {:?}) => {:?}", input, stored_locals, out);
-    out
 }
 
 /// For every saved local, looks for which locals are StorageLive at the same
@@ -575,11 +597,11 @@ fn renumber_bitset(
 /// computation; see `GeneratorLayout` for more.
 fn compute_storage_conflicts(
     body: &'mir Body<'tcx>,
-    stored_locals: &BitSet<Local>,
+    saved_locals: &GeneratorSavedLocals,
     always_live_locals: storage::AlwaysLiveLocals,
     requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
-    assert_eq!(body.local_decls.len(), stored_locals.domain_size());
+    assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
     debug!("compute_storage_conflicts({:?})", body.span);
     debug!("always_live = {:?}", always_live_locals);
@@ -587,12 +609,12 @@ fn compute_storage_conflicts(
     // Locals that are always live or ones that need to be stored across
     // suspension points are not eligible for overlap.
     let mut ineligible_locals = always_live_locals.into_inner();
-    ineligible_locals.intersect(stored_locals);
+    ineligible_locals.intersect(saved_locals);
 
     // Compute the storage conflicts for all eligible locals.
     let mut visitor = StorageConflictVisitor {
         body,
-        stored_locals: &stored_locals,
+        saved_locals: &saved_locals,
         local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
     };
 
@@ -609,16 +631,14 @@ fn compute_storage_conflicts(
     // However, in practice these bitsets are not usually large. The layout code
     // also needs to keep track of how many conflicts each local has, so it's
     // simpler to keep it this way for now.
-    let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count());
-    for (idx_a, local_a) in stored_locals.iter().enumerate() {
-        let saved_local_a = GeneratorSavedLocal::new(idx_a);
+    let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count());
+    for (saved_local_a, local_a) in saved_locals.iter_enumerated() {
         if ineligible_locals.contains(local_a) {
             // Conflicts with everything.
             storage_conflicts.insert_all_into_row(saved_local_a);
         } else {
             // Keep overlap information only for stored locals.
-            for (idx_b, local_b) in stored_locals.iter().enumerate() {
-                let saved_local_b = GeneratorSavedLocal::new(idx_b);
+            for (saved_local_b, local_b) in saved_locals.iter_enumerated() {
                 if local_conflicts.contains(local_a, local_b) {
                     storage_conflicts.insert(saved_local_a, saved_local_b);
                 }
@@ -630,7 +650,7 @@ fn compute_storage_conflicts(
 
 struct StorageConflictVisitor<'mir, 'tcx, 's> {
     body: &'mir Body<'tcx>,
-    stored_locals: &'s BitSet<Local>,
+    saved_locals: &'s GeneratorSavedLocals,
     // FIXME(tmandry): Consider using sparse bitsets here once we have good
     // benchmarks for generators.
     local_conflicts: BitMatrix<Local, Local>,
@@ -666,7 +686,7 @@ fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
         }
 
         let mut eligible_storage_live = flow_state.clone();
-        eligible_storage_live.intersect(&self.stored_locals);
+        eligible_storage_live.intersect(&self.saved_locals);
 
         for local in eligible_storage_live.iter() {
             self.local_conflicts.union_row_with(&eligible_storage_live, local);
@@ -678,7 +698,7 @@ fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
     }
 }
 
-/// Validates the typeck view of the generator against the actual set of types retained between
+/// Validates the typeck view of the generator against the actual set of types saved between
 /// yield points.
 fn sanitize_witness<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -686,7 +706,7 @@ fn sanitize_witness<'tcx>(
     did: DefId,
     witness: Ty<'tcx>,
     upvars: &Vec<Ty<'tcx>>,
-    retained: &BitSet<Local>,
+    saved_locals: &GeneratorSavedLocals,
 ) {
     let allowed_upvars = tcx.erase_regions(upvars);
     let allowed = match witness.kind {
@@ -703,8 +723,8 @@ fn sanitize_witness<'tcx>(
     let param_env = tcx.param_env(did);
 
     for (local, decl) in body.local_decls.iter_enumerated() {
-        // Ignore locals which are internal or not retained between yields.
-        if !retained.contains(local) || decl.internal {
+        // Ignore locals which are internal or not saved between yields.
+        if !saved_locals.contains(local) || decl.internal {
             continue;
         }
         let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty);
@@ -724,35 +744,27 @@ fn sanitize_witness<'tcx>(
 }
 
 fn compute_layout<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    source: MirSource<'tcx>,
-    upvars: &Vec<Ty<'tcx>>,
-    interior: Ty<'tcx>,
-    always_live_locals: &storage::AlwaysLiveLocals,
-    movable: bool,
+    liveness: LivenessInfo,
     body: &mut Body<'tcx>,
 ) -> (
     FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
     GeneratorLayout<'tcx>,
     IndexVec<BasicBlock, Option<BitSet<Local>>>,
 ) {
-    // Use a liveness analysis to compute locals which are live across a suspension point
     let LivenessInfo {
-        live_locals,
+        saved_locals,
         live_locals_at_suspension_points,
         storage_conflicts,
         storage_liveness,
-    } = locals_live_across_suspend_points(tcx, body, source, always_live_locals, movable);
-
-    sanitize_witness(tcx, body, source.def_id(), interior, upvars, &live_locals);
+    } = liveness;
 
     // Gather live local types and their indices.
     let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
     let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
-    for (idx, local) in live_locals.iter().enumerate() {
+    for (saved_local, local) in saved_locals.iter_enumerated() {
         locals.push(local);
         tys.push(body.local_decls[local].ty);
-        debug!("generator saved local {:?} => {:?}", GeneratorSavedLocal::from(idx), local);
+        debug!("generator saved local {:?} => {:?}", saved_local, local);
     }
 
     // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
@@ -1260,11 +1272,25 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
 
         let always_live_locals = storage::AlwaysLiveLocals::new(&body);
 
+        let liveness_info =
+            locals_live_across_suspend_points(tcx, body, source, &always_live_locals, movable);
+
+        sanitize_witness(tcx, body, def_id, interior, &upvars, &liveness_info.saved_locals);
+
+        if tcx.sess.opts.debugging_opts.validate_mir {
+            let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
+                assigned_local: None,
+                saved_locals: &liveness_info.saved_locals,
+                storage_conflicts: &liveness_info.storage_conflicts,
+            };
+
+            vis.visit_body(body);
+        }
+
         // Extract locals which are live across suspension point into `layout`
         // `remap` gives a mapping from local indices onto generator struct indices
         // `storage_liveness` tells us which locals have live storage at suspension points
-        let (remap, layout, storage_liveness) =
-            compute_layout(tcx, source, &upvars, interior, &always_live_locals, movable, body);
+        let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
 
         let can_return = can_return(tcx, body);
 
@@ -1315,3 +1341,134 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
         create_generator_resume_function(tcx, transform, source, body, can_return);
     }
 }
+
+/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
+/// in the generator state machine but whose storage is not marked as conflicting
+///
+/// Validation needs to happen immediately *before* `TransformVisitor` is invoked, not after.
+///
+/// This condition would arise when the assignment is the last use of `_5` but the initial
+/// definition of `_4` if we weren't extra careful to mark all locals used inside a statement as
+/// conflicting. Non-conflicting generator saved locals may be stored at the same location within
+/// the generator state machine, which would result in ill-formed MIR: the left-hand and right-hand
+/// sides of an assignment may not alias. This caused a miscompilation in [#73137].
+///
+/// [#73137]: https://github.com/rust-lang/rust/issues/73137
+struct EnsureGeneratorFieldAssignmentsNeverAlias<'a> {
+    saved_locals: &'a GeneratorSavedLocals,
+    storage_conflicts: &'a BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
+    assigned_local: Option<GeneratorSavedLocal>,
+}
+
+impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
+    fn saved_local_for_direct_place(&self, place: Place<'_>) -> Option<GeneratorSavedLocal> {
+        if place.is_indirect() {
+            return None;
+        }
+
+        self.saved_locals.get(place.local)
+    }
+
+    fn check_assigned_place(&mut self, place: Place<'tcx>, f: impl FnOnce(&mut Self)) {
+        if let Some(assigned_local) = self.saved_local_for_direct_place(place) {
+            assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse");
+
+            self.assigned_local = Some(assigned_local);
+            f(self);
+            self.assigned_local = None;
+        }
+    }
+}
+
+impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
+    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
+        let lhs = match self.assigned_local {
+            Some(l) => l,
+            None => {
+                // This visitor only invokes `visit_place` for the right-hand side of an assignment
+                // and only after setting `self.assigned_local`. However, the default impl of
+                // `Visitor::super_body` may call `visit_place` with a `NonUseContext` for places
+                // with debuginfo. Ignore them here.
+                assert!(!context.is_use());
+                return;
+            }
+        };
+
+        let rhs = match self.saved_local_for_direct_place(*place) {
+            Some(l) => l,
+            None => return,
+        };
+
+        if !self.storage_conflicts.contains(lhs, rhs) {
+            bug!(
+                "Assignment between generator saved locals whose storage is not \
+                    marked as conflicting: {:?}: {:?} = {:?}",
+                location,
+                lhs,
+                rhs,
+            );
+        }
+    }
+
+    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+        match &statement.kind {
+            StatementKind::Assign(box (lhs, rhs)) => {
+                self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
+            }
+
+            // FIXME: Does `llvm_asm!` have any aliasing requirements?
+            StatementKind::LlvmInlineAsm(_) => {}
+
+            StatementKind::FakeRead(..)
+            | StatementKind::SetDiscriminant { .. }
+            | StatementKind::StorageLive(_)
+            | StatementKind::StorageDead(_)
+            | StatementKind::Retag(..)
+            | StatementKind::AscribeUserType(..)
+            | StatementKind::Nop => {}
+        }
+    }
+
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        // Checking for aliasing in terminators is probably overkill, but until we have actual
+        // semantics, we should be conservative here.
+        match &terminator.kind {
+            TerminatorKind::Call {
+                func,
+                args,
+                destination: Some((dest, _)),
+                cleanup: _,
+                from_hir_call: _,
+                fn_span: _,
+            } => {
+                self.check_assigned_place(*dest, |this| {
+                    this.visit_operand(func, location);
+                    for arg in args {
+                        this.visit_operand(arg, location);
+                    }
+                });
+            }
+
+            TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
+                self.check_assigned_place(*resume_arg, |this| this.visit_operand(value, location));
+            }
+
+            // FIXME: Does `asm!` have any aliasing requirements?
+            TerminatorKind::InlineAsm { .. } => {}
+
+            TerminatorKind::Call { .. }
+            | TerminatorKind::Goto { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Abort
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::Drop { .. }
+            | TerminatorKind::DropAndReplace { .. }
+            | TerminatorKind::Assert { .. }
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::FalseUnwind { .. } => {}
+        }
+    }
+}
index c36614938e10f9ab8b9a006faae3becece49105b..06b648ab5a908dd3710b02d5cbdde751cfdf4c11 100644 (file)
@@ -1,10 +1,19 @@
 use crate::transform::{MirPass, MirSource};
 use crate::util::patch::MirPatch;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::lang_items;
-use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::*;
+use rustc_middle::hir;
+use rustc_middle::ich::StableHashingContext;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::{
+    self, traversal, BasicBlock, BasicBlockData, CoverageData, Operand, Place, SourceInfo,
+    StatementKind, Terminator, TerminatorKind, START_BLOCK,
+};
 use rustc_middle::ty;
+use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ConstKind, FnDef};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
 /// the intrinsic llvm.instrprof.increment.
 pub struct InstrumentCoverage;
 
+/// The `query` provider for `CoverageData`, requested by `codegen_intrinsic_call()` when
+/// constructing the arguments for `llvm.instrprof.increment`.
+pub(crate) fn provide(providers: &mut Providers<'_>) {
+    providers.coverage_data = |tcx, def_id| {
+        let mir_body = tcx.optimized_mir(def_id);
+        // FIXME(richkadel): The current implementation assumes the MIR for the given DefId
+        // represents a single function. Validate and/or correct if inlining and/or monomorphization
+        // invalidates these assumptions.
+        let count_code_region_fn =
+            tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None);
+        let mut num_counters: u32 = 0;
+        // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected
+        // counters, with each counter having an index from `0..num_counters-1`. MIR optimization
+        // may split and duplicate some BasicBlock sequences. Simply counting the calls may not
+        // not work; but computing the num_counters by adding `1` to the highest index (for a given
+        // instrumented function) is valid.
+        for (_, data) in traversal::preorder(mir_body) {
+            if let Some(terminator) = &data.terminator {
+                if let TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
+                    &terminator.kind
+                {
+                    if let FnDef(called_fn_def_id, _) = func.literal.ty.kind {
+                        if called_fn_def_id == count_code_region_fn {
+                            if let Operand::Constant(constant) =
+                                args.get(0).expect("count_code_region has at least one arg")
+                            {
+                                if let ConstKind::Value(ConstValue::Scalar(value)) =
+                                    constant.literal.val
+                                {
+                                    let index = value
+                                        .to_u32()
+                                        .expect("count_code_region index at arg0 is u32");
+                                    num_counters = std::cmp::max(num_counters, index + 1);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        let hash = if num_counters > 0 { hash_mir_source(tcx, def_id) } else { 0 };
+        CoverageData { num_counters, hash }
+    };
+}
+
+struct Instrumentor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    num_counters: u32,
+}
+
 impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &mut mir::Body<'tcx>) {
         if tcx.sess.opts.debugging_opts.instrument_coverage {
-            debug!("instrumenting {:?}", src.def_id());
-            instrument_coverage(tcx, body);
+            // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
+            // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
+            if src.promoted.is_none() {
+                debug!(
+                    "instrumenting {:?}, span: {}",
+                    src.def_id(),
+                    tcx.sess.source_map().span_to_string(mir_body.span)
+                );
+                Instrumentor::new(tcx).inject_counters(mir_body);
+            }
         }
     }
 }
 
-// The first counter (start of the function) is index zero.
-const INIT_FUNCTION_COUNTER: u32 = 0;
-
-/// Injects calls to placeholder function `count_code_region()`.
-// FIXME(richkadel): As a first step, counters are only injected at the top of each function.
-// The complete solution will inject counters at each conditional code branch.
-pub fn instrument_coverage<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let span = body.span.shrink_to_lo();
-
-    let count_code_region_fn = function_handle(
-        tcx,
-        tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None),
-        span,
-    );
-    let counter_index = Operand::const_from_scalar(
-        tcx,
-        tcx.types.u32,
-        Scalar::from_u32(INIT_FUNCTION_COUNTER),
-        span,
-    );
-
-    let mut patch = MirPatch::new(body);
-
-    let new_block = patch.new_block(placeholder_block(SourceInfo::outermost(body.span)));
-    let next_block = START_BLOCK;
-
-    let temp = patch.new_temp(tcx.mk_unit(), body.span);
-    patch.patch_terminator(
-        new_block,
-        TerminatorKind::Call {
-            func: count_code_region_fn,
-            args: vec![counter_index],
-            // new_block will swapped with the next_block, after applying patch
-            destination: Some((Place::from(temp), new_block)),
-            cleanup: None,
-            from_hir_call: false,
-            fn_span: span,
-        },
-    );
-
-    patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp));
-    patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp));
-
-    patch.apply(body);
-
-    // To insert the `new_block` in front of the first block in the counted branch (for example,
-    // the START_BLOCK, at the top of the function), just swap the indexes, leaving the rest of the
-    // graph unchanged.
-    body.basic_blocks_mut().swap(next_block, new_block);
+impl<'tcx> Instrumentor<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx, num_counters: 0 }
+    }
+
+    fn next_counter(&mut self) -> u32 {
+        let next = self.num_counters;
+        self.num_counters += 1;
+        next
+    }
+
+    fn inject_counters(&mut self, mir_body: &mut mir::Body<'tcx>) {
+        // FIXME(richkadel): As a first step, counters are only injected at the top of each
+        // function. The complete solution will inject counters at each conditional code branch.
+        let top_of_function = START_BLOCK;
+        let entire_function = mir_body.span;
+
+        self.inject_counter(mir_body, top_of_function, entire_function);
+    }
+
+    fn inject_counter(
+        &mut self,
+        mir_body: &mut mir::Body<'tcx>,
+        next_block: BasicBlock,
+        code_region: Span,
+    ) {
+        let injection_point = code_region.shrink_to_lo();
+
+        let count_code_region_fn = function_handle(
+            self.tcx,
+            self.tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None),
+            injection_point,
+        );
+        let counter_index = Operand::const_from_scalar(
+            self.tcx,
+            self.tcx.types.u32,
+            Scalar::from_u32(self.next_counter()),
+            injection_point,
+        );
+
+        let mut patch = MirPatch::new(mir_body);
+
+        let temp = patch.new_temp(self.tcx.mk_unit(), code_region);
+        let new_block = patch.new_block(placeholder_block(code_region));
+        patch.patch_terminator(
+            new_block,
+            TerminatorKind::Call {
+                func: count_code_region_fn,
+                args: vec![counter_index],
+                // new_block will swapped with the next_block, after applying patch
+                destination: Some((Place::from(temp), new_block)),
+                cleanup: None,
+                from_hir_call: false,
+                fn_span: injection_point,
+            },
+        );
+
+        patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp));
+        patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp));
+
+        patch.apply(mir_body);
+
+        // To insert the `new_block` in front of the first block in the counted branch (the
+        // `next_block`), just swap the indexes, leaving the rest of the graph unchanged.
+        mir_body.basic_blocks_mut().swap(next_block, new_block);
+    }
 }
 
 fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Operand<'tcx> {
@@ -79,14 +163,31 @@ fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Ope
     Operand::function_handle(tcx, fn_def_id, substs, span)
 }
 
-fn placeholder_block<'tcx>(source_info: SourceInfo) -> BasicBlockData<'tcx> {
+fn placeholder_block(span: Span) -> BasicBlockData<'tcx> {
     BasicBlockData {
         statements: vec![],
         terminator: Some(Terminator {
-            source_info,
+            source_info: SourceInfo::outermost(span),
             // this gets overwritten by the counter Call
             kind: TerminatorKind::Unreachable,
         }),
         is_cleanup: false,
     }
 }
+
+fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> u64 {
+    let hir_node = tcx.hir().get_if_local(def_id).expect("DefId is local");
+    let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
+    let hir_body = tcx.hir().body(fn_body_id);
+    let mut hcx = tcx.create_no_span_stable_hashing_context();
+    hash(&mut hcx, &hir_body.value).to_smaller_hash()
+}
+
+fn hash(
+    hcx: &mut StableHashingContext<'tcx>,
+    node: &impl HashStable<StableHashingContext<'tcx>>,
+) -> Fingerprint {
+    let mut stable_hasher = StableHasher::new();
+    node.hash_stable(hcx, &mut stable_hasher);
+    stable_hasher.finish()
+}
index 846ed1f86d8d6ab996bd664edc191aaa460331f9..8ca240d2c7da77eeffcc15137d77304ed3ba7706 100644 (file)
@@ -56,6 +56,7 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
         promoted_mir,
         ..*providers
     };
+    instrument_coverage::provide(providers);
 }
 
 fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
index 47ae92c48bd88dce1277adb8d348326d69646aba..7811d5fb741b27d946b6ce57c6856d8d2b4977d5 100644 (file)
@@ -1151,7 +1151,7 @@ fn parse_abi(&mut self) -> Option<StrLit> {
     /// This restriction shouldn't be an issue in practice,
     /// since this function is used to record the tokens for
     /// a parsed AST item, which always has matching delimiters.
-    fn collect_tokens<R>(
+    pub fn collect_tokens<R>(
         &mut self,
         f: impl FnOnce(&mut Self) -> PResult<'a, R>,
     ) -> PResult<'a, (R, TokenStream)> {
index 80681c143750fc7e8fe091158cfc49a891aa7c35..408f2e8c19a5de1642bf102668cfbb1a069b21c3 100644 (file)
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
-fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
+pub(crate) fn target_from_impl_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_item: &hir::ImplItem<'_>,
+) -> Target {
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
index 779fb8039d15713b08bc38b06f285c29500c7f5a..f4167c8644e6edc36b17ff2ec2d50d591ee564df 100644 (file)
@@ -7,17 +7,19 @@
 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
 //! * Functions called by the compiler itself.
 
+use crate::check_attr::target_from_impl_item;
 use crate::weak_lang_items;
 
 use rustc_middle::middle::cstore::ExternCrate;
 use rustc_middle::ty::TyCtxt;
 
+use rustc_ast::ast::Attribute;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items::{extract, ITEM_REFS};
-use rustc_hir::{LangItem, LanguageItems, Target};
+use rustc_hir::{HirId, LangItem, LanguageItems, Target};
 
 use rustc_middle::ty::query::Providers;
 
@@ -28,12 +30,37 @@ struct LanguageItemCollector<'tcx> {
 
 impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        if let Some((value, span)) = extract(&item.attrs) {
-            let actual_target = Target::from_item(item);
+        self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs)
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
+        self.check_for_lang(
+            Target::from_trait_item(trait_item),
+            trait_item.hir_id,
+            trait_item.attrs,
+        )
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
+        self.check_for_lang(
+            target_from_impl_item(self.tcx, impl_item),
+            impl_item.hir_id,
+            impl_item.attrs,
+        )
+    }
+}
+
+impl LanguageItemCollector<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
+        LanguageItemCollector { tcx, items: LanguageItems::new() }
+    }
+
+    fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
+        if let Some((value, span)) = extract(&attrs) {
             match ITEM_REFS.get(&*value.as_str()).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
-                    let def_id = self.tcx.hir().local_def_id(item.hir_id);
+                    let def_id = self.tcx.hir().local_def_id(hir_id);
                     self.collect_item(item_index, def_id.to_def_id());
                 }
                 // Known lang item with attribute on incorrect target.
@@ -71,20 +98,6 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
         }
     }
 
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {
-        // At present, lang items are always items, not trait items.
-    }
-
-    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
-        // At present, lang items are always items, not impl items.
-    }
-}
-
-impl LanguageItemCollector<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
-        LanguageItemCollector { tcx, items: LanguageItems::new() }
-    }
-
     fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
         // Check for duplicates.
         if let Some(original_def_id) = self.items.items[item_index] {
index fa5c557b5d9c647a94d6a6a267410c160d2f4b9d..6f6104c3d6932f5783edb6156444b713bc368a4f 100644 (file)
@@ -24,6 +24,7 @@ rustc_errors = { path = "../librustc_errors" }
 rustc_expand = { path = "../librustc_expand" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_index = { path = "../librustc_index" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
index 8432e34a5271ceef7ddc9eed6de8b256f671f5cb..ef43f597eab4754df4325d7e1cb6ab9893be50fb 100644 (file)
@@ -19,6 +19,7 @@
 use rustc_ast::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind};
 use rustc_ast::token::{self, Token};
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast_lowering::Resolver as ResolverAstLowering;
 use rustc_attr as attr;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability};
@@ -171,7 +172,7 @@ impl<'a> Resolver<'a> {
         fragment: &AstFragment,
         parent_scope: ParentScope<'a>,
     ) -> MacroRulesScope<'a> {
-        collect_definitions(&mut self.definitions, fragment, parent_scope.expansion);
+        collect_definitions(self, fragment, parent_scope.expansion);
         let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
         fragment.visit_with(&mut visitor);
         visitor.parent_scope.macro_rules
@@ -647,9 +648,9 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                 } else if orig_name == Some(kw::SelfLower) {
                     self.r.graph_root
                 } else {
-                    let def_id = self.r.definitions.local_def_id(item.id);
+                    let def_id = self.r.local_def_id(item.id);
                     let crate_id =
-                        self.r.crate_loader.process_extern_crate(item, &self.r.definitions);
+                        self.r.crate_loader.process_extern_crate(item, &self.r.definitions, def_id);
                     self.r.extern_crate_map.insert(def_id, crate_id);
                     self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
                 };
@@ -704,7 +705,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
 
             ItemKind::Mod(..) => {
-                let def_id = self.r.definitions.local_def_id(item.id);
+                let def_id = self.r.local_def_id(item.id);
                 let module_kind = ModuleKind::Def(DefKind::Mod, def_id.to_def_id(), ident.name);
                 let module = self.r.arenas.alloc_module(ModuleData {
                     no_implicit_prelude: parent.no_implicit_prelude || {
@@ -727,18 +728,15 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
 
             // These items live in the value namespace.
             ItemKind::Static(..) => {
-                let res =
-                    Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Const(..) => {
-                let res =
-                    Res::Def(DefKind::Const, self.r.definitions.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Const, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Fn(..) => {
-                let res =
-                    Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
 
                 // Functions introducing procedural macros reserve a slot
@@ -748,15 +746,12 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
 
             // These items live in the type namespace.
             ItemKind::TyAlias(..) => {
-                let res = Res::Def(
-                    DefKind::TyAlias,
-                    self.r.definitions.local_def_id(item.id).to_def_id(),
-                );
+                let res = Res::Def(DefKind::TyAlias, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             ItemKind::Enum(_, _) => {
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
                 self.r.variant_vis.insert(def_id, vis);
                 let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name);
                 let module = self.r.new_module(
@@ -771,17 +766,14 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             }
 
             ItemKind::TraitAlias(..) => {
-                let res = Res::Def(
-                    DefKind::TraitAlias,
-                    self.r.definitions.local_def_id(item.id).to_def_id(),
-                );
+                let res = Res::Def(DefKind::TraitAlias, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             // These items live in both the type and value namespaces.
             ItemKind::Struct(ref vdata, _) => {
                 // Define a name in the type namespace.
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
                 let res = Res::Def(DefKind::Struct, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
@@ -814,7 +806,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                     }
                     let ctor_res = Res::Def(
                         DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
-                        self.r.definitions.local_def_id(ctor_node_id).to_def_id(),
+                        self.r.local_def_id(ctor_node_id).to_def_id(),
                     );
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis));
@@ -822,7 +814,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             }
 
             ItemKind::Union(ref vdata, _) => {
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
                 let res = Res::Def(DefKind::Union, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
@@ -831,7 +823,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             }
 
             ItemKind::Trait(..) => {
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
 
                 // Add all the items within to a new module.
                 let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
@@ -856,18 +848,15 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
     /// Constructs the reduced graph for one foreign item.
     fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
         let (res, ns) = match item.kind {
-            ForeignItemKind::Fn(..) => (
-                Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id).to_def_id()),
-                ValueNS,
-            ),
-            ForeignItemKind::Static(..) => (
-                Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id).to_def_id()),
-                ValueNS,
-            ),
-            ForeignItemKind::TyAlias(..) => (
-                Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id).to_def_id()),
-                TypeNS,
-            ),
+            ForeignItemKind::Fn(..) => {
+                (Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id()), ValueNS)
+            }
+            ForeignItemKind::Static(..) => {
+                (Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id()), ValueNS)
+            }
+            ForeignItemKind::TyAlias(..) => {
+                (Res::Def(DefKind::ForeignTy, self.r.local_def_id(item.id).to_def_id()), TypeNS)
+            }
             ForeignItemKind::MacCall(_) => unreachable!(),
         };
         let parent = self.parent_scope.module;
@@ -1170,7 +1159,7 @@ fn insert_unused_macro(
     fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> {
         let parent_scope = self.parent_scope;
         let expansion = parent_scope.expansion;
-        let def_id = self.r.definitions.local_def_id(item.id);
+        let def_id = self.r.local_def_id(item.id);
         let (ext, ident, span, macro_rules) = match &item.kind {
             ItemKind::MacroDef(def) => {
                 let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition()));
@@ -1315,7 +1304,7 @@ fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
         }
 
         // Add the item to the trait info.
-        let item_def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+        let item_def_id = self.r.local_def_id(item.id).to_def_id();
         let (res, ns) = match item.kind {
             AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
             AssocItemKind::Fn(_, ref sig, _, _) => {
@@ -1417,7 +1406,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         let ident = variant.ident;
 
         // Define a name in the type namespace.
-        let def_id = self.r.definitions.local_def_id(variant.id).to_def_id();
+        let def_id = self.r.local_def_id(variant.id).to_def_id();
         let res = Res::Def(DefKind::Variant, def_id);
         self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
 
@@ -1435,7 +1424,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         // It's ok to use the variant's id as a ctor id since an
         // error will be reported on any use of such resolution anyway.
         let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id);
-        let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id).to_def_id();
+        let ctor_def_id = self.r.local_def_id(ctor_node_id).to_def_id();
         let ctor_kind = CtorKind::from_ast(&variant.data);
         let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
         self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
index cc0e97aeb14300ce1cf8fa8a47cb2ac1ea8d3766..0ca01a384e73ef108313f9c00cf942c1b9014fa9 100644 (file)
@@ -29,6 +29,7 @@
 use rustc_ast::ast;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::visit::{self, Visitor};
+use rustc_ast_lowering::Resolver as ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::pluralize;
 use rustc_middle::ty;
@@ -64,7 +65,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
     fn check_import(&mut self, id: ast::NodeId) {
         let mut used = false;
         self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
-        let def_id = self.r.definitions.local_def_id(id);
+        let def_id = self.r.local_def_id(id);
         if !used {
             if self.r.maybe_unused_trait_imports.contains(&def_id) {
                 // Check later.
@@ -246,7 +247,7 @@ impl Resolver<'_> {
                     }
                 }
                 ImportKind::ExternCrate { .. } => {
-                    let def_id = self.definitions.local_def_id(import.id);
+                    let def_id = self.local_def_id(import.id);
                     self.maybe_unused_extern_crates.push((def_id, import.span));
                 }
                 ImportKind::MacroUse => {
index 71cedb208fcf283edd49328fb6be8016c891bf54..f1063f42c91ecb295ea84920ca14f288ea1eff60 100644 (file)
@@ -1,8 +1,10 @@
+use crate::Resolver;
 use log::debug;
 use rustc_ast::ast::*;
 use rustc_ast::token::{self, Token};
 use rustc_ast::visit::{self, FnKind};
 use rustc_ast::walk_list;
+use rustc_ast_lowering::Resolver as ResolverAstLowering;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::definitions::*;
 use rustc_span::Span;
 
 crate fn collect_definitions(
-    definitions: &mut Definitions,
+    resolver: &mut Resolver<'_>,
     fragment: &AstFragment,
     expansion: ExpnId,
 ) {
-    let parent_def = definitions.invocation_parent(expansion);
-    fragment.visit_with(&mut DefCollector { definitions, parent_def, expansion });
+    let parent_def = resolver.invocation_parents[&expansion];
+    fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion });
 }
 
 /// Creates `DefId`s for nodes in the AST.
-struct DefCollector<'a> {
-    definitions: &'a mut Definitions,
+struct DefCollector<'a, 'b> {
+    resolver: &'a mut Resolver<'b>,
     parent_def: LocalDefId,
     expansion: ExpnId,
 }
 
-impl<'a> DefCollector<'a> {
+impl<'a, 'b> DefCollector<'a, 'b> {
     fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
         let parent_def = self.parent_def;
         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
-        self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
+        self.resolver.create_def(parent_def, node_id, data, self.expansion, span)
     }
 
     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
@@ -43,12 +45,13 @@ fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
         let index = |this: &Self| {
             index.unwrap_or_else(|| {
                 let node_id = NodeId::placeholder_from_expn_id(this.expansion);
-                this.definitions.placeholder_field_index(node_id)
+                this.resolver.placeholder_field_indices[&node_id]
             })
         };
 
         if field.is_placeholder {
-            self.definitions.set_placeholder_field_index(field.id, index(self));
+            let old_index = self.resolver.placeholder_field_indices.insert(field.id, index(self));
+            assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
             self.visit_macro_invoc(field.id);
         } else {
             let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
@@ -58,11 +61,13 @@ fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
     }
 
     fn visit_macro_invoc(&mut self, id: NodeId) {
-        self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
+        let old_parent =
+            self.resolver.invocation_parents.insert(id.placeholder_to_expn_id(), self.parent_def);
+        assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
     }
 }
 
-impl<'a> visit::Visitor<'a> for DefCollector<'a> {
+impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
     fn visit_item(&mut self, i: &'a Item) {
         debug!("visit_item: {:?}", i);
 
index bb88b8191f1adb6729c6293112dede99d8db46e3..2854683b61bab30919de6906f8f421150d5f0dc4 100644 (file)
@@ -108,7 +108,7 @@ impl<'a> Resolver<'a> {
                 match outer_res {
                     Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
                         if let Some(impl_span) =
-                            maybe_impl_defid.and_then(|def_id| self.definitions.opt_span(def_id))
+                            maybe_impl_defid.and_then(|def_id| self.opt_span(def_id))
                         {
                             err.span_label(
                                 reduce_impl_span_to_impl_keyword(sm, impl_span),
@@ -127,12 +127,12 @@ impl<'a> Resolver<'a> {
                         return err;
                     }
                     Res::Def(DefKind::TyParam, def_id) => {
-                        if let Some(span) = self.definitions.opt_span(def_id) {
+                        if let Some(span) = self.opt_span(def_id) {
                             err.span_label(span, "type parameter from outer function");
                         }
                     }
                     Res::Def(DefKind::ConstParam, def_id) => {
-                        if let Some(span) = self.definitions.opt_span(def_id) {
+                        if let Some(span) = self.opt_span(def_id) {
                             err.span_label(span, "const parameter from outer function");
                         }
                     }
@@ -643,18 +643,18 @@ fn lookup_import_candidates_from_module<FilterFn>(
         let not_local_module = crate_name.name != kw::Crate;
         let mut worklist =
             vec![(start_module, Vec::<ast::PathSegment>::new(), true, not_local_module)];
+        let mut worklist_via_import = vec![];
 
-        while let Some((in_module, path_segments, accessible, in_module_is_extern)) = worklist.pop()
+        while let Some((in_module, path_segments, accessible, in_module_is_extern)) =
+            match worklist.pop() {
+                None => worklist_via_import.pop(),
+                Some(x) => Some(x),
+            }
         {
             // We have to visit module children in deterministic order to avoid
             // instabilities in reported imports (#43552).
             in_module.for_each_child(self, |this, ident, ns, name_binding| {
-                // avoid imports entirely
-                if name_binding.is_import() && !name_binding.is_extern_crate() {
-                    return;
-                }
-
-                // avoid non-importable candidates as well
+                // avoid non-importable candidates
                 if !name_binding.is_importable() {
                     return;
                 }
@@ -667,6 +667,17 @@ fn lookup_import_candidates_from_module<FilterFn>(
                     return;
                 }
 
+                let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
+
+                // There is an assumption elsewhere that paths of variants are in the enum's
+                // declaration and not imported. With this assumption, the variant component is
+                // chopped and the rest of the path is assumed to be the enum's own path. For
+                // errors where a variant is used as the type instead of the enum, this causes
+                // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
+                if via_import && name_binding.is_possibly_imported_variant() {
+                    return;
+                }
+
                 // collect results based on the filter function
                 // avoid suggesting anything from the same module in which we are resolving
                 if ident.name == lookup_ident.name
@@ -724,7 +735,8 @@ fn lookup_import_candidates_from_module<FilterFn>(
                         let is_extern = in_module_is_extern || name_binding.is_extern_crate();
                         // add the module to the lookup
                         if seen_modules.insert(module.def_id().unwrap()) {
-                            worklist.push((module, path_segments, child_accessible, is_extern));
+                            if via_import { &mut worklist_via_import } else { &mut worklist }
+                                .push((module, path_segments, child_accessible, is_extern));
                         }
                     }
                 }
@@ -846,7 +858,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
                 Applicability::MaybeIncorrect,
             );
             let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
-                LOCAL_CRATE => self.definitions.opt_span(def_id),
+                LOCAL_CRATE => self.opt_span(def_id),
                 _ => Some(
                     self.session
                         .source_map()
index 74a8b7e2f556d3c05310419d84cd5ffb32cb07c5..8a6541b399e381e8ff8e746978f26300e2f012b7 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_ast::ast::NodeId;
 use rustc_ast::unwrap_or;
 use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast_lowering::Resolver as ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
@@ -1393,7 +1394,7 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
             let is_good_import =
                 binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
             if is_good_import || binding.is_macro_def() {
-                let res = binding.res().map_id(|id| this.definitions.local_def_id(id));
+                let res = binding.res().map_id(|id| this.local_def_id(id));
                 if res != def::Res::Err {
                     reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
                 }
index 61f20df8cc6c03151a23cee02aaf63f95c88d501..6f769c3c59cae6fda1efdecd28104866d245ddea 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{unwrap_or, walk_list};
+use rustc_ast_lowering::Resolver as ResolverAstLowering;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
@@ -707,7 +708,7 @@ fn with_rib<T>(
     }
 
     fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
-        let id = self.r.definitions.local_def_id(id);
+        let id = self.r.local_def_id(id);
         let module = self.r.module_map.get(&id).cloned(); // clones a reference
         if let Some(module) = module {
             // Move down in the graph.
@@ -759,7 +760,7 @@ fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         debug!("resolve_adt");
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                let item_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+                let item_def_id = this.r.local_def_id(item.id).to_def_id();
                 this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
                     visit::walk_item(this, item);
                 });
@@ -839,7 +840,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
             ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let local_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+                    let local_def_id = this.r.local_def_id(item.id).to_def_id();
                     this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
                         walk_list!(this, visit_param_bound, bounds);
@@ -880,7 +881,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
             ItemKind::TraitAlias(ref generics, ref bounds) => {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let local_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+                    let local_def_id = this.r.local_def_id(item.id).to_def_id();
                     this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
                         walk_list!(this, visit_param_bound, bounds);
@@ -961,7 +962,7 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib
             seen_bindings.entry(ident).or_insert(param.ident.span);
 
             // Plain insert (no renaming).
-            let res = Res::Def(def_kind, self.r.definitions.local_def_id(param.id).to_def_id());
+            let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
 
             match param.kind {
                 GenericParamKind::Type { .. } => {
@@ -1111,7 +1112,7 @@ fn resolve_implementation(
             this.with_self_rib(Res::SelfTy(None, None), |this| {
                 // Resolve the trait reference, if necessary.
                 this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
-                    let item_def_id = this.r.definitions.local_def_id(item_id).to_def_id();
+                    let item_def_id = this.r.local_def_id(item_id).to_def_id();
                     this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
                         if let Some(trait_ref) = opt_trait_reference.as_ref() {
                             // Resolve type arguments in the trait path.
@@ -2002,7 +2003,7 @@ fn resolve_block(&mut self, block: &'ast Block) {
             if let StmtKind::Item(ref item) = stmt.kind {
                 if let ItemKind::MacroDef(..) = item.kind {
                     num_macro_definition_ribs += 1;
-                    let res = self.r.definitions.local_def_id(item.id).to_def_id();
+                    let res = self.r.local_def_id(item.id).to_def_id();
                     self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
                     self.label_ribs.push(Rib::new(MacroDefinition(res)));
                 }
@@ -2296,7 +2297,7 @@ fn find_transitive_imports(
     ) -> SmallVec<[LocalDefId; 1]> {
         let mut import_ids = smallvec![];
         while let NameBindingKind::Import { import, binding, .. } = kind {
-            let id = self.r.definitions.local_def_id(import.id);
+            let id = self.r.local_def_id(import.id);
             self.r.maybe_unused_trait_imports.insert(id);
             self.r.add_to_glob_map(&import, trait_name);
             import_ids.push(id);
index 478698ba20c70b4d36d64e4bf1954e4b7548f3c4..1bce160acb6100ebbb2d23edd8c6a2d49f484ab1 100644 (file)
@@ -512,7 +512,7 @@ fn smart_resolve_context_dependent_help(
                 _ => {}
             }
             if !suggested {
-                if let Some(span) = self.r.definitions.opt_span(def_id) {
+                if let Some(span) = self.r.opt_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
                 }
                 err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str));
@@ -536,7 +536,7 @@ fn smart_resolve_context_dependent_help(
                 if nightly_options::is_nightly_build() {
                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
                                `type` alias";
-                    if let Some(span) = self.r.definitions.opt_span(def_id) {
+                    if let Some(span) = self.r.opt_span(def_id) {
                         err.span_help(span, msg);
                     } else {
                         err.help(msg);
@@ -593,7 +593,7 @@ fn smart_resolve_context_dependent_help(
                 bad_struct_syntax_suggestion(def_id);
             }
             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
-                if let Some(span) = self.r.definitions.opt_span(def_id) {
+                if let Some(span) = self.r.opt_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
                 }
                 err.span_label(span, format!("did you mean `{}( /* fields */ )`?", path_str));
index 91bd155614178b67831ef649e6308133f2f74985..9ddcf9e1de7d191dabb0db017b6eeef9f83ac653 100644 (file)
@@ -27,6 +27,7 @@
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::unwrap_or;
 use rustc_ast::visit::{self, Visitor};
+use rustc_ast_lowering::Resolver as ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
-use rustc_hir::definitions::{DefKey, Definitions};
+use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
 use rustc_hir::TraitCandidate;
+use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::hir::exports::ExportMap;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
@@ -256,31 +258,21 @@ fn from(seg: &'a ast::PathSegment) -> Segment {
     }
 }
 
-struct UsePlacementFinder<'d> {
-    definitions: &'d Definitions,
-    target_module: LocalDefId,
+struct UsePlacementFinder {
+    target_module: NodeId,
     span: Option<Span>,
     found_use: bool,
 }
 
-impl<'d> UsePlacementFinder<'d> {
-    fn check(
-        definitions: &'d Definitions,
-        krate: &Crate,
-        target_module: DefId,
-    ) -> (Option<Span>, bool) {
-        if let Some(target_module) = target_module.as_local() {
-            let mut finder =
-                UsePlacementFinder { definitions, target_module, span: None, found_use: false };
-            visit::walk_crate(&mut finder, krate);
-            (finder.span, finder.found_use)
-        } else {
-            (None, false)
-        }
+impl UsePlacementFinder {
+    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
+        let mut finder = UsePlacementFinder { target_module, span: None, found_use: false };
+        visit::walk_crate(&mut finder, krate);
+        (finder.span, finder.found_use)
     }
 }
 
-impl<'tcx, 'd> Visitor<'tcx> for UsePlacementFinder<'d> {
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     fn visit_mod(
         &mut self,
         module: &'tcx ast::Mod,
@@ -291,7 +283,7 @@ fn visit_mod(
         if self.span.is_some() {
             return;
         }
-        if self.definitions.local_def_id(node_id) != self.target_module {
+        if node_id != self.target_module {
             visit::walk_mod(self, module);
             return;
         }
@@ -711,6 +703,13 @@ fn is_ambiguity(&self) -> bool {
             }
     }
 
+    fn is_possibly_imported_variant(&self) -> bool {
+        match self.kind {
+            NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
+            _ => self.is_variant(),
+        }
+    }
+
     // We sometimes need to treat variants as `pub` for backwards compatibility.
     fn pseudo_vis(&self) -> ty::Visibility {
         if self.is_variant() && self.res().def_id().is_local() {
@@ -979,6 +978,19 @@ pub struct Resolver<'a> {
     lint_buffer: LintBuffer,
 
     next_node_id: NodeId,
+
+    def_id_to_span: IndexVec<LocalDefId, Span>,
+
+    node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
+    def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
+
+    /// Indices of unnamed struct or variant fields with unresolved attributes.
+    placeholder_field_indices: FxHashMap<NodeId, usize>,
+    /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
+    /// we know what parent node that fragment should be attached to thanks to this table.
+    invocation_parents: FxHashMap<ExpnId, LocalDefId>,
+
+    next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1042,7 +1054,7 @@ fn parent(self, id: DefId) -> Option<DefId> {
 
 /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
 /// the resolver is no longer needed as all the relevant information is inline.
-impl rustc_ast_lowering::Resolver for Resolver<'_> {
+impl ResolverAstLowering for Resolver<'_> {
     fn def_key(&mut self, id: DefId) -> DefKey {
         if let Some(id) = id.as_local() {
             self.definitions().def_key(id)
@@ -1113,6 +1125,56 @@ fn next_node_id(&mut self) -> NodeId {
     fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
         &self.trait_map
     }
+
+    fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
+        self.node_id_to_def_id.get(&node).copied()
+    }
+
+    fn local_def_id(&self, node: NodeId) -> LocalDefId {
+        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+    }
+
+    /// Adds a definition with a parent definition.
+    fn create_def(
+        &mut self,
+        parent: LocalDefId,
+        node_id: ast::NodeId,
+        data: DefPathData,
+        expn_id: ExpnId,
+        span: Span,
+    ) -> LocalDefId {
+        assert!(
+            !self.node_id_to_def_id.contains_key(&node_id),
+            "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
+            node_id,
+            data,
+            self.definitions.def_key(self.node_id_to_def_id[&node_id]),
+        );
+
+        // Find the next free disambiguator for this key.
+        let next_disambiguator = &mut self.next_disambiguator;
+        let next_disambiguator = |parent, data| {
+            let next_disamb = next_disambiguator.entry((parent, data)).or_insert(0);
+            let disambiguator = *next_disamb;
+            *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
+            disambiguator
+        };
+
+        let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator);
+
+        assert_eq!(self.def_id_to_span.push(span), def_id);
+
+        // Some things for which we allocate `LocalDefId`s don't correspond to
+        // anything in the AST, so they don't have a `NodeId`. For these cases
+        // we don't need a mapping from `NodeId` to `LocalDefId`.
+        if node_id != ast::DUMMY_NODE_ID {
+            debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
+            self.node_id_to_def_id.insert(node_id, def_id);
+        }
+        assert_eq!(self.def_id_to_node_id.push(node_id), def_id);
+
+        def_id
+    }
 }
 
 impl<'a> Resolver<'a> {
@@ -1143,8 +1205,18 @@ pub fn new(
         let mut module_map = FxHashMap::default();
         module_map.insert(LocalDefId { local_def_index: CRATE_DEF_INDEX }, graph_root);
 
-        let mut definitions = Definitions::default();
-        definitions.create_root_def(crate_name, session.local_crate_disambiguator());
+        let definitions = Definitions::new(crate_name, session.local_crate_disambiguator());
+        let root = definitions.get_root_def();
+
+        let mut def_id_to_span = IndexVec::default();
+        assert_eq!(def_id_to_span.push(rustc_span::DUMMY_SP), root);
+        let mut def_id_to_node_id = IndexVec::default();
+        assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
+        let mut node_id_to_def_id = FxHashMap::default();
+        node_id_to_def_id.insert(CRATE_NODE_ID, root);
+
+        let mut invocation_parents = FxHashMap::default();
+        invocation_parents.insert(ExpnId::root(), root);
 
         let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
             .opts
@@ -1263,6 +1335,12 @@ pub fn new(
             variant_vis: Default::default(),
             lint_buffer: LintBuffer::default(),
             next_node_id: NodeId::from_u32(1),
+            def_id_to_span,
+            node_id_to_def_id,
+            def_id_to_node_id,
+            placeholder_field_indices: Default::default(),
+            invocation_parents,
+            next_disambiguator: Default::default(),
         }
     }
 
@@ -1457,7 +1535,7 @@ fn record_use(
     #[inline]
     fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) {
         if import.is_glob() {
-            let def_id = self.definitions.local_def_id(import.id);
+            let def_id = self.local_def_id(import.id);
             self.glob_map.entry(def_id).or_default().insert(ident.name);
         }
     }
@@ -2538,7 +2616,11 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
         for UseError { mut err, candidates, def_id, instead, suggestion } in
             self.use_injections.drain(..)
         {
-            let (span, found_use) = UsePlacementFinder::check(&self.definitions, krate, def_id);
+            let (span, found_use) = if let Some(def_id) = def_id.as_local() {
+                UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
+            } else {
+                (None, false)
+            };
             if !candidates.is_empty() {
                 diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use);
             } else if let Some((span, msg, sugg, appl)) = suggestion {
@@ -2934,6 +3016,12 @@ pub fn graph_root(&self) -> Module<'a> {
     pub fn all_macros(&self) -> &FxHashMap<Symbol, Res> {
         &self.all_macros
     }
+
+    /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
+    #[inline]
+    pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
+        if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
+    }
 }
 
 fn names_to_string(names: &[Symbol]) -> String {
index 1b49722355e54133bf79c9a2cfc0fc732753a883..398b0e92d9d8cf5fcbfb531b7ed84661aa882798 100644 (file)
@@ -7,6 +7,7 @@
 use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
 use rustc_ast::ast::{self, NodeId};
+use rustc_ast_lowering::Resolver as ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, StabilityLevel};
 use rustc_data_structures::fx::FxHashSet;
@@ -190,7 +191,7 @@ fn expansion_for_ast_pass(
         )));
 
         let parent_scope = if let Some(module_id) = parent_module_id {
-            let parent_def_id = self.definitions.local_def_id(module_id);
+            let parent_def_id = self.local_def_id(module_id);
             self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id.to_def_id());
             self.module_map[&parent_def_id]
         } else {
@@ -340,7 +341,9 @@ fn check_unused_macros(&mut self) {
     }
 
     fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
-        self.definitions.lint_node_id(expn_id)
+        self.invocation_parents
+            .get(&expn_id)
+            .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
     }
 
     fn has_derive_copy(&self, expn_id: ExpnId) -> bool {
index f77bf5ddefd3f430904812ed30864a9908df6d4e..c5a866817cb4a1930a5b085f22f32d11d50212c2 100644 (file)
@@ -1849,6 +1849,7 @@ fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMo
                 }
             }
         };
+        log::debug!("got unpretty option: {:?}", first);
         first
     }
 }
@@ -1977,9 +1978,11 @@ pub fn needs_ast_map(&self) -> bool {
         use PpMode::*;
         use PpSourceMode::*;
         match *self {
-            PpmSource(PpmNormal | PpmEveryBodyLoops | PpmIdentified) => false,
+            PpmSource(PpmNormal | PpmIdentified) => false,
 
-            PpmSource(PpmExpanded | PpmExpandedIdentified | PpmExpandedHygiene)
+            PpmSource(
+                PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
+            )
             | PpmHir(_)
             | PpmHirTree(_)
             | PpmMir
index 5586b82b0edc082f8c5001b0516ee001b5963a52..27396c524f4e6f4134dfeee763fd2f77a7cf283f 100644 (file)
@@ -41,7 +41,7 @@ pub fn get_lib_path(&self) -> PathBuf {
         make_target_lib_path(self.sysroot, self.triple)
     }
 
-    pub fn get_selfcontained_lib_path(&self) -> PathBuf {
+    pub fn get_self_contained_lib_path(&self) -> PathBuf {
         self.get_lib_path().join("self-contained")
     }
 
@@ -92,13 +92,13 @@ pub fn search_path_dirs(&self) -> Vec<PathBuf> {
     }
 
     // Returns a list of directories where target-specific tool binaries are located.
-    pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
+    pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
         let mut p = PathBuf::from(self.sysroot);
         p.push(find_libdir(self.sysroot).as_ref());
         p.push(RUST_LIB_DIR);
         p.push(&self.triple);
         p.push("bin");
-        vec![p.clone(), p.join("self-contained")]
+        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p.clone()] }
     }
 }
 
index 6c6f27502b6142d6b8cbc7fabbe501af634d3019..9337f241d7022fd322a2a708cba2fde5271ee716 100644 (file)
@@ -880,14 +880,18 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         (such as entering an empty infinite loop) by inserting llvm.sideeffect \
         (default: no)"),
     instrument_coverage: bool = (false, parse_bool, [TRACKED],
-        "instrument the generated code with LLVM code region counters to \
-        (in the future) generate coverage reports (experimental; default: no)"),
+        "instrument the generated code with LLVM code region counters to (in the \
+        future) generate coverage reports (default: no; note, the compiler build \
+        config must include `profiler = true`)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
         "keep hygiene data after analysis (default: no)"),
     link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
         "link native libraries in the linker invocation (default: yes)"),
+    link_self_contained: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "control whether to link Rust provided C objects/libraries or rely
+         on C toolchain installed in the system"),
     link_only: bool = (false, parse_bool, [TRACKED],
         "link the `.rlink` file generated by `-Z no-link` (default: no)"),
     llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
index ddbc95fb1b0b8ed61888b9b91a4829924aec1913..f4e5da4d54f46e9d6749568c21d02f0efb59e8cb 100644 (file)
@@ -13,6 +13,7 @@
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::{MultiSpan, Span, Symbol};
 
+use std::collections::BTreeMap;
 use std::path::PathBuf;
 use std::str;
 
@@ -63,7 +64,7 @@ pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
 #[derive(Default)]
 pub struct SymbolGallery {
     /// All symbols occurred and their first occurrance span.
-    pub symbols: Lock<FxHashMap<Symbol, Span>>,
+    pub symbols: Lock<BTreeMap<Symbol, Span>>,
 }
 
 impl SymbolGallery {
index 07b05d37ed303c3d723b0151da8733349fae6fef..857734037afe7c588dfa6b07d30be60234b94852 100644 (file)
         assume_init,
         async_await,
         async_closure,
+        atomics,
         attr,
         attributes,
         attr_literals,
         proc_macro_mod,
         proc_macro_non_items,
         proc_macro_path_invoc,
+        profiler_builtins,
         profiler_runtime,
         ptr_guaranteed_eq,
         ptr_guaranteed_ne,
index b07c2aef1caca004bbc07a3844652ad43157070f..0d0a0da9d1c4cb9a2ff069dfc5fd0a8b2706d7a0 100644 (file)
@@ -141,7 +141,6 @@ pub fn opts(arch: Arch, os: AppleOS) -> Result<TargetOptions, String> {
     let pre_link_args = build_pre_link_args(arch, os)?;
     Ok(TargetOptions {
         cpu: target_cpu(arch),
-        dynamic_linking: false,
         executables: true,
         pre_link_args,
         link_env_remove: link_env_remove(arch),
index bc696214cbc66a82b532026b13562fec715ffd2c..f71b3fcf129da4e9225f4d67f80e613866ea37d6 100644 (file)
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
+use rustc_hir::lang_items::{FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem};
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 
 pub use rustc_middle::traits::Reveal;
@@ -1399,8 +1399,8 @@ fn confirm_callable_candidate<'cx, 'tcx>(
 
     debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
 
-    // the `Output` associated type is declared on `FnOnce`
     let fn_once_def_id = tcx.require_lang_item(FnOnceTraitLangItem, None);
+    let fn_once_output_def_id = tcx.require_lang_item(FnOnceOutputLangItem, None);
 
     let predicate = super::util::closure_trait_ref_and_return_type(
         tcx,
@@ -1410,11 +1410,10 @@ fn confirm_callable_candidate<'cx, 'tcx>(
         flag,
     )
     .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
-        projection_ty: ty::ProjectionTy::from_ref_and_name(
-            tcx,
-            trait_ref,
-            Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME),
-        ),
+        projection_ty: ty::ProjectionTy {
+            substs: trait_ref.substs,
+            item_def_id: fn_once_output_def_id,
+        },
         ty: ret_type,
     });
 
index bcfc0cf347cbcf94c9144615ef4b6f47bbc2bfbb..85c073ca3003439aec9fd2e5a057e11e2239aa0e 100644 (file)
@@ -34,6 +34,7 @@ pub fn emit_coerce_suggestions(
         }
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
         self.suggest_missing_await(err, expr, expected, expr_ty);
+        self.note_need_for_fn_pointer(err, expected, expr_ty);
     }
 
     // Requires that the two types unify, and prints an error message if
index 1594d65e9bdee2c54effc76cfab16febb2973f17..0325782e69d516a17d127c8ad2bc2b835723e9d4 100644 (file)
@@ -5362,6 +5362,43 @@ fn suggest_missing_await(
         }
     }
 
+    fn note_need_for_fn_pointer(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        let (sig, did, substs) = match (&expected.kind, &found.kind) {
+            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                if sig1 != sig2 {
+                    return;
+                }
+                err.note(
+                    "different `fn` items always have unique types, even if their signatures are \
+                     the same",
+                );
+                (sig1, *did1, substs1)
+            }
+            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
+                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+                if sig1 != *sig2 {
+                    return;
+                }
+                (sig1, *did, substs)
+            }
+            _ => return,
+        };
+        err.help(&format!("change the expected type to be function pointer `{}`", sig));
+        err.help(&format!(
+            "if the expected type is due to type inference, cast the expected `fn` to a function \
+             pointer: `{} as {}`",
+            self.tcx.def_path_str_with_substs(did, substs),
+            sig
+        ));
+    }
+
     /// A common error is to add an extra semicolon:
     ///
     /// ```
index 5c76c840b1ddd1910238457bd4aadbdd011fe404..6dec016cc2ee3d7a0c70de06ce58d2567510d912 100644 (file)
@@ -486,6 +486,33 @@ pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> {
         })
     }
 
+    /// Enforce the format of attributes inside `#[doc(...)]`.
+    pub fn check_doc_attributes(
+        diagnostic: &::rustc_errors::Handler,
+        mi: &ast::MetaItem,
+    ) -> Option<(String, String)> {
+        mi.meta_item_list().and_then(|list| {
+            for meta in list {
+                if meta.check_name(sym::alias) {
+                    if !meta.is_value_str()
+                        || meta
+                            .value_str()
+                            .map(|s| s.to_string())
+                            .unwrap_or_else(String::new)
+                            .is_empty()
+                    {
+                        diagnostic.span_err(
+                            meta.span(),
+                            "doc alias attribute expects a string: #[doc(alias = \"0\")]",
+                        );
+                    }
+                }
+            }
+
+            None
+        })
+    }
+
     pub fn has_doc_flag(&self, flag: Symbol) -> bool {
         for attr in &self.other_attrs {
             if !attr.check_name(sym::doc) {
@@ -529,6 +556,7 @@ pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute])
                 } else {
                     if attr.check_name(sym::doc) {
                         if let Some(mi) = attr.meta() {
+                            Attributes::check_doc_attributes(&diagnostic, &mi);
                             if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
                                 // Extracted #[doc(cfg(...))]
                                 match Cfg::parse(cfg_mi) {
index 8d53b0579537407c8abbf5c66c2566baacb58b71..59bb206678f5106329806dbfde372a5708b4da43 100644 (file)
@@ -1015,12 +1015,13 @@ function defocusSearchBar() {
                 var aliases = [];
                 var crateAliases = [];
                 var i;
-                if (filterCrates !== undefined &&
-                        ALIASES[filterCrates] &&
-                        ALIASES[filterCrates][query.search]) {
-                    for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
-                        aliases.push(
-                            createAliasFromItem(searchIndex[ALIASES[filterCrates][query.search]]));
+                if (filterCrates !== undefined) {
+                    if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
+                        for (i = 0; i < ALIASES[filterCrates][query.search].length; ++i) {
+                            aliases.push(
+                                createAliasFromItem(
+                                    searchIndex[ALIASES[filterCrates][query.search][i]]));
+                        }
                     }
                 } else {
                     Object.keys(ALIASES).forEach(function(crate) {
index a4996d9eee810d0c2654aedda0fe3b048684522d..6d98c4d01c040d1449cfd15c90d8a9c2051528c1 100644 (file)
@@ -1009,9 +1009,93 @@ mod return_keyword {}
 //
 /// The receiver of a method, or the current module.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `self` is used in two situations: referencing the current module and marking
+/// the receiver of a method.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// In paths, `self` can be used to refer to the current module, either in a
+/// [`use`] statement or in a path to access an element:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io::{self, Read};
+/// ```
+///
+/// Is functionally the same as:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io;
+/// use std::io::Read;
+/// ```
+///
+/// Using `self` to access an element in the current module:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// # fn main() {}
+/// fn foo() {}
+/// fn bar() {
+///     self::foo()
+/// }
+/// ```
+///
+/// `self` as the current receiver for a method allows to omit the parameter
+/// type most of the time. With the exception of this particularity, `self` is
+/// used much like any other parameter:
+///
+/// ```
+/// struct Foo(i32);
+///
+/// impl Foo {
+///     // No `self`.
+///     fn new() -> Self {
+///         Self(0)
+///     }
+///
+///     // Consuming `self`.
+///     fn consume(self) -> Self {
+///         Self(self.0 + 1)
+///     }
+///
+///     // Borrowing `self`.
+///     fn borrow(&self) -> &i32 {
+///         &self.0
+///     }
+///
+///     // Borrowing `self` mutably.
+///     fn borrow_mut(&mut self) -> &mut i32 {
+///         &mut self.0
+///     }
+/// }
+///
+/// // This method must be called with a `Type::` prefix.
+/// let foo = Foo::new();
+/// assert_eq!(foo.0, 0);
+///
+/// // Those two calls produces the same result.
+/// let foo = Foo::consume(foo);
+/// assert_eq!(foo.0, 1);
+/// let foo = foo.consume();
+/// assert_eq!(foo.0, 2);
+///
+/// // Borrowing is handled automatically with the second syntax.
+/// let borrow_1 = Foo::borrow(&foo);
+/// let borrow_2 = foo.borrow();
+/// assert_eq!(borrow_1, borrow_2);
+///
+/// // Borrowing mutably is handled automatically too with the second syntax.
+/// let mut foo = Foo::new();
+/// *Foo::borrow_mut(&mut foo) += 1;
+/// assert_eq!(foo.0, 1);
+/// *foo.borrow_mut() += 1;
+/// assert_eq!(foo.0, 2);
+/// ```
+///
+/// Note that this automatic conversion when calling `foo.method()` is not
+/// limited to the examples above. See the [Reference] for more information.
+///
+/// [`use`]: keyword.use.html
+/// [Reference]: ../reference/items/associated-items.html#methods
 mod self_keyword {}
 
 #[doc(keyword = "Self")]
index 2abbf1fa9fa16197ef270fd9e1bd50ae3c8ec73c..b668aa2595d67bc4dc81fe18ba7ea69f26f9e20c 100644 (file)
@@ -1,7 +1,5 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
-use libc;
-
 use crate::fs::Metadata;
 use crate::sys_common::AsInner;
 
index d22ac1d53858429dcc45c9fcbd9c16ce98926400..97d62d958ca4f873462378bac4a8d7b0ec3add64 100644 (file)
@@ -170,7 +170,7 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
 fn default_hook(info: &PanicInfo<'_>) {
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
-    let backtrace_env = if update_panic_count(0) >= 2 {
+    let backtrace_env = if panic_count::get() >= 2 {
         RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
     } else {
         backtrace::rust_backtrace_env()
@@ -221,19 +221,65 @@ fn default_hook(info: &PanicInfo<'_>) {
 #[cfg(not(test))]
 #[doc(hidden)]
 #[unstable(feature = "update_panic_count", issue = "none")]
-pub fn update_panic_count(amt: isize) -> usize {
+pub mod panic_count {
     use crate::cell::Cell;
-    thread_local! { static PANIC_COUNT: Cell<usize> = Cell::new(0) }
+    use crate::sync::atomic::{AtomicUsize, Ordering};
+
+    // Panic count for the current thread.
+    thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = Cell::new(0) }
+
+    // Sum of panic counts from all threads. The purpose of this is to have
+    // a fast path in `is_zero` (which is used by `panicking`). Access to
+    // this variable can be always be done with relaxed ordering because
+    // it is always guaranteed that, if `GLOBAL_PANIC_COUNT` is zero,
+    // `LOCAL_PANIC_COUNT` will be zero.
+    static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
+
+    pub fn increase() -> usize {
+        GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
+        LOCAL_PANIC_COUNT.with(|c| {
+            let next = c.get() + 1;
+            c.set(next);
+            next
+        })
+    }
+
+    pub fn decrease() -> usize {
+        GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed);
+        LOCAL_PANIC_COUNT.with(|c| {
+            let next = c.get() - 1;
+            c.set(next);
+            next
+        })
+    }
 
-    PANIC_COUNT.with(|c| {
-        let next = (c.get() as isize + amt) as usize;
-        c.set(next);
-        next
-    })
+    pub fn get() -> usize {
+        LOCAL_PANIC_COUNT.with(|c| c.get())
+    }
+
+    #[inline]
+    pub fn is_zero() -> bool {
+        if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) == 0 {
+            // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads
+            // (including the current one) will have `LOCAL_PANIC_COUNT`
+            // equal to zero, so TLS access can be avoided.
+            true
+        } else {
+            is_zero_slow_path()
+        }
+    }
+
+    // Slow path is in a separate function to reduce the amount of code
+    // inlined from `is_zero`.
+    #[inline(never)]
+    #[cold]
+    fn is_zero_slow_path() -> bool {
+        LOCAL_PANIC_COUNT.with(|c| c.get() == 0)
+    }
 }
 
 #[cfg(test)]
-pub use realstd::rt::update_panic_count;
+pub use realstd::rt::panic_count;
 
 /// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
 pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
@@ -283,7 +329,7 @@ union Data<F, R> {
     #[cold]
     unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
         let obj = Box::from_raw(__rust_panic_cleanup(payload));
-        update_panic_count(-1);
+        panic_count::decrease();
         obj
     }
 
@@ -312,8 +358,9 @@ fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
 }
 
 /// Determines whether the current thread is unwinding because of panic.
+#[inline]
 pub fn panicking() -> bool {
-    update_panic_count(0) != 0
+    !panic_count::is_zero()
 }
 
 /// The entry point for panicking with a formatted message.
@@ -445,7 +492,7 @@ fn rust_panic_with_hook(
     message: Option<&fmt::Arguments<'_>>,
     location: &Location<'_>,
 ) -> ! {
-    let panics = update_panic_count(1);
+    let panics = panic_count::increase();
 
     // If this is the third nested call (e.g., panics == 2, this is 0-indexed),
     // the panic hook probably triggered the last panic, otherwise the
@@ -495,7 +542,7 @@ fn rust_panic_with_hook(
 /// This is the entry point for `resume_unwind`.
 /// It just forwards the payload to the panic runtime.
 pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
-    update_panic_count(1);
+    panic_count::increase();
 
     struct RewrapBox(Box<dyn Any + Send>);
 
index 2426b2dead71209db4b14842c6cf7e05171ead3c..fb825ab16ebd7ef8d1dc114bd8d0a36b86a461fe 100644 (file)
@@ -15,7 +15,7 @@
 #![doc(hidden)]
 
 // Re-export some of our utilities which are expected by other crates.
-pub use crate::panicking::{begin_panic, begin_panic_fmt, update_panic_count};
+pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
 
 // To reduce the generated code of the new `lang_start`, this function is doing
 // the real work.
index 87e7a5da2b7a9b179eaa0222305f89914fbd4efb..5ef26d4cc4dc65a52d3e4e2eb6d92f4990585c22 100644 (file)
@@ -56,6 +56,7 @@
 // able to specify this
 #[cfg(not(test))]
 #[no_mangle]
+#[allow(improper_ctypes_definitions)]
 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
     // FIXME: how to support TLS in library mode?
     let tls = Box::new(tls::Tls::new());
index cd24605ec7ab724650fd971ba2ce96aec7c0085a..ada8eaa1c9745e61fe2810eb3d99575008574ecc 100644 (file)
@@ -2,9 +2,6 @@
 
 //! Unix-specific networking functionality
 
-#[cfg(unix)]
-use libc;
-
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
 #[cfg(not(unix))]
 #[allow(non_camel_case_types)]
index efd615f404db6b316e89c57b3fe5bbe47ef7abd2..adff6c489bbc90b0cf27ff4a07230456f4bbf57e 100644 (file)
@@ -56,7 +56,6 @@ mod imp {
     use crate::ffi::{CStr, OsString};
     use crate::marker::PhantomData;
     use crate::ptr;
-    use libc;
 
     use crate::sys_common::mutex::Mutex;
 
index 9864a855df738ef0afc3353cfc40959f463449c3..7cc64658ee1a9d1dd6d45fe14efbe60dea4618f7 100644 (file)
@@ -6,7 +6,6 @@
 use crate::sys;
 use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-use libc;
 
 /// Unix-specific extensions to [`File`].
 ///
index 87ebd2c9593fc936a10fd699ecb3346aad22ea9d..3a1ff5fd3b9c64c4edb2ac96368b647f08aba4dd 100644 (file)
@@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 mod imp {
     use crate::io;
     use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
-    use libc;
 
     pub fn fill_bytes(v: &mut [u8]) {
         static RNG_INIT: AtomicBool = AtomicBool::new(false);
index fd2e1a6e7bcfb99311ac2d4a9d50ce1c3e8e279a..c90304c2b4a6a2d90dede9cd798a4b6d4063a8aa 100644 (file)
@@ -1,6 +1,5 @@
 use crate::cell::UnsafeCell;
 use crate::sync::atomic::{AtomicUsize, Ordering};
-use libc;
 
 pub struct RWLock {
     inner: UnsafeCell<libc::pthread_rwlock_t>,
index 8ebbf89213f321bfbdf27111ec4e3d86a57a0ef5..8365c9ee9c995dbdd70c045e30fb573dac424eeb 100644 (file)
@@ -1,7 +1,6 @@
 use crate::cmp::Ordering;
 use crate::time::Duration;
 use ::core::hash::{Hash, Hasher};
-use libc;
 
 pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
 use crate::convert::TryInto;
@@ -104,7 +103,6 @@ mod inner {
     use crate::fmt;
     use crate::sys::cvt;
     use crate::time::Duration;
-    use libc;
 
     use super::Timespec;
 
index bc614162784010e98e580f2257afbd18bf5b05fe..57187851a14e37c57cff6a173f6f6dd4cc9c152a 100644 (file)
@@ -1,7 +1,6 @@
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ptr;
 use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-use libc;
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
index 7071f31dbf104d60324aee2279332ba9825053a7..7ceec94d81e762ee32c19c428f6be95179eb9f7a 100644 (file)
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
--         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: usize
-+                                          // + val: Value(Scalar(0x00000003))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
-+         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x00))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
           assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
index 15995ab070019842123a9424033798a69999a48d..483a6f232ef79677a0b2b7e31425a61d3b80f6bf 100644 (file)
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
--         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: usize
-+                                          // + val: Value(Scalar(0x0000000000000003))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
-+         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x00))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
           assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
diff --git a/src/test/mir-opt/const_prop_miscompile.rs b/src/test/mir-opt/const_prop_miscompile.rs
new file mode 100644 (file)
index 0000000..043b228
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(raw_ref_op)]
+
+// EMIT_MIR rustc.foo.ConstProp.diff
+fn foo() {
+    let mut u = (1,);
+    *&mut u.0 = 5;
+    let y = { u.0 } == 5;
+}
+
+// EMIT_MIR rustc.bar.ConstProp.diff
+fn bar() {
+    let mut v = (1,);
+    unsafe {
+        *&raw mut v.0 = 5;
+    }
+    let y = { v.0 } == 5;
+}
+
+fn main() {
+    foo();
+    bar();
+}
diff --git a/src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff
new file mode 100644 (file)
index 0000000..c87f67b
--- /dev/null
@@ -0,0 +1,75 @@
+- // MIR for `bar` before ConstProp
++ // MIR for `bar` after ConstProp
+  
+  fn bar() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:11:10: 11:10
+      let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+      let _2: ();                          // in scope 0 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+      let mut _3: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+      let mut _5: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+      scope 1 {
+          debug v => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+          let _4: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          scope 2 {
+          }
+          scope 3 {
+              debug y => _4;               // in scope 3 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+-         _1 = (const 1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
++         _1 = const (1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
+                                           // ty::Const
+-                                          // + ty: i32
++                                          // + ty: (i32,)
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+-                                          // + span: $DIR/const_prop_miscompile.rs:12:18: 12:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/const_prop_miscompile.rs:12:17: 12:21
++                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+          StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+          _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+          (*_3) = const 5i32;              // scope 2 at $DIR/const_prop_miscompile.rs:14:9: 14:26
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:14:25: 14:26
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:26: 14:27
+          _2 = const ();                   // scope 2 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:13:5: 15:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:15:5: 15:6
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          StorageLive(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+          _5 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:16:15: 16:18
+          _4 = Eq(move _5, const 5i32);    // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:16:24: 16:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:24: 16:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:11:10: 17:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:11:10: 17:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+          StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+          return;                          // scope 0 at $DIR/const_prop_miscompile.rs:17:2: 17:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff
new file mode 100644 (file)
index 0000000..8a6850d
--- /dev/null
@@ -0,0 +1,63 @@
+- // MIR for `foo` before ConstProp
++ // MIR for `foo` after ConstProp
+  
+  fn foo() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:4:10: 4:10
+      let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+      let mut _2: &mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+      let mut _4: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+      scope 1 {
+          debug u => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+          let _3: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          scope 2 {
+              debug y => _3;               // in scope 2 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+-         _1 = (const 1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
++         _1 = const (1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
+                                           // ty::Const
+-                                          // + ty: i32
++                                          // + ty: (i32,)
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+-                                          // + span: $DIR/const_prop_miscompile.rs:5:18: 5:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/const_prop_miscompile.rs:5:17: 5:21
++                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+          _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+          (*_2) = const 5i32;              // scope 1 at $DIR/const_prop_miscompile.rs:6:5: 6:18
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:6:17: 6:18
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:18: 6:19
+          StorageLive(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+          _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:7:15: 7:18
+          _3 = Eq(move _4, const 5i32);    // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:7:24: 7:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:24: 7:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:4:10: 8:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:4:10: 8:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+          StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/const_prop_miscompile.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/rustdoc-js/doc-alias-filter-out.js b/src/test/rustdoc-js/doc-alias-filter-out.js
new file mode 100644 (file)
index 0000000..46a089d
--- /dev/null
@@ -0,0 +1,9 @@
+// exact-check
+
+const QUERY = 'true';
+
+const FILTER_CRATE = 'some_other_crate';
+
+const EXPECTED = {
+    'others': [],
+};
diff --git a/src/test/rustdoc-js/doc-alias-filter-out.rs b/src/test/rustdoc-js/doc-alias-filter-out.rs
new file mode 100644 (file)
index 0000000..815e8ce
--- /dev/null
@@ -0,0 +1,4 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "true")]
+pub struct Foo;
diff --git a/src/test/rustdoc-js/doc-alias-filter.js b/src/test/rustdoc-js/doc-alias-filter.js
new file mode 100644 (file)
index 0000000..4b1e2e2
--- /dev/null
@@ -0,0 +1,17 @@
+// exact-check
+
+const QUERY = 'true';
+
+const FILTER_CRATE = 'doc_alias_filter';
+
+const EXPECTED = {
+    'others': [
+        {
+            'path': 'doc_alias_filter',
+            'name': 'Foo',
+            'alias': 'true',
+            'href': '../doc_alias_filter/struct.Foo.html',
+            'is_alias': true
+        },
+    ],
+};
diff --git a/src/test/rustdoc-js/doc-alias-filter.rs b/src/test/rustdoc-js/doc-alias-filter.rs
new file mode 100644 (file)
index 0000000..8887f8c
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "true")]
+pub struct Foo;
+
+#[doc(alias = "false")]
+pub struct Bar;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs
new file mode 100644 (file)
index 0000000..2f01099
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "foo")] // ok!
+pub struct Bar;
+
+#[doc(alias)] //~ ERROR
+#[doc(alias = 0)] //~ ERROR
+#[doc(alias("bar"))] //~ ERROR
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
new file mode 100644 (file)
index 0000000..480acc8
--- /dev/null
@@ -0,0 +1,20 @@
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:6:7
+   |
+LL | #[doc(alias)]
+   |       ^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:7:7
+   |
+LL | #[doc(alias = 0)]
+   |       ^^^^^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:8:7
+   |
+LL | #[doc(alias("bar"))]
+   |       ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index fcdff59ffa984cd9b9b58754248715aabd437891..32864dba4587eb20722ba4925734f77e18a3d8d7 100644 (file)
@@ -38,6 +38,7 @@ pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
 
 #[cfg(target_arch = "x86_64")]
 #[inline(never)]
+#[allow(improper_ctypes_definitions)]
 pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct {
     foo.0 *= 1;
     foo.1 *= 2;
index 09abe4fbf7e095f96d245879ecd47a4e4f8d4bb7..f77f40998de012ec0abdf81e11e41e59d453da54 100644 (file)
@@ -10,6 +10,7 @@
 #[repr(align(16))]
 pub struct A(i64);
 
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn foo(x: A) {}
 
 fn main() {
diff --git a/src/test/ui/assoc-lang-items.rs b/src/test/ui/assoc-lang-items.rs
new file mode 100644 (file)
index 0000000..23453d2
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(lang_items)]
+
+trait Foo {
+    #[lang = "dummy_lang_item_1"] //~ ERROR definition
+    fn foo() {}
+
+    #[lang = "dummy_lang_item_2"] //~ ERROR definition
+    fn bar();
+
+    #[lang = "dummy_lang_item_3"] //~ ERROR definition
+    type MyType;
+}
+
+struct Bar;
+
+impl Bar {
+    #[lang = "dummy_lang_item_4"] //~ ERROR definition
+    fn test() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/assoc-lang-items.stderr b/src/test/ui/assoc-lang-items.stderr
new file mode 100644 (file)
index 0000000..040792f
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0522]: definition of an unknown language item: `dummy_lang_item_1`
+  --> $DIR/assoc-lang-items.rs:4:5
+   |
+LL |     #[lang = "dummy_lang_item_1"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_1`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_2`
+  --> $DIR/assoc-lang-items.rs:7:5
+   |
+LL |     #[lang = "dummy_lang_item_2"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_2`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_3`
+  --> $DIR/assoc-lang-items.rs:10:5
+   |
+LL |     #[lang = "dummy_lang_item_3"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_3`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_4`
+  --> $DIR/assoc-lang-items.rs:17:5
+   |
+LL |     #[lang = "dummy_lang_item_4"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_4`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0522`.
index 68b75c18a43dc52769978449b88d3496156599fc..abae40162a0fcacdfc6f58397fc0fa8622f60204 100644 (file)
@@ -12,22 +12,44 @@ impl<T> Foo for T { /* `foo` is still default here */ }
 fn main() {
     eq(foo::<u8>, bar::<u8>);
     //~^ ERROR mismatched types
-    //~|  expected fn item `fn(_) -> _ {foo::<u8>}`
-    //~|  found fn item `fn(_) -> _ {bar::<u8>}`
-    //~|  expected fn item, found a different fn item
+    //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+    //~| found fn item `fn(_) -> _ {bar::<u8>}`
+    //~| expected fn item, found a different fn item
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
 
     eq(foo::<u8>, foo::<i8>);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `i8`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
 
     eq(bar::<String>, bar::<Vec<u8>>);
     //~^ ERROR mismatched types
-    //~|  expected fn item `fn(_) -> _ {bar::<std::string::String>}`
-    //~|  found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
-    //~|  expected struct `std::string::String`, found struct `std::vec::Vec`
+    //~| expected fn item `fn(_) -> _ {bar::<std::string::String>}`
+    //~| found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+    //~| expected struct `std::string::String`, found struct `std::vec::Vec`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
 
     // Make sure we distinguish between trait methods correctly.
     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `u16`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+
+    eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+    //~^ ERROR mismatched types
+    //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+    //~| found fn pointer `fn(_) -> _`
+    //~| expected fn item, found fn pointer
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+
+    eq(foo::<u8> as fn(isize) -> isize, bar::<u8>); // ok!
 }
index 4cce25c43c485b31eb8e73bedbc392db400c8a74..bfa9efa219f4c8aa71c2df4a1a00e8e0820f74d8 100644 (file)
@@ -6,34 +6,57 @@ LL |     eq(foo::<u8>, bar::<u8>);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {bar::<u8>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:19:19
+  --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
    |                   ^^^^^^^^^ expected `u8`, found `i8`
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {foo::<i8>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:23:23
+  --> $DIR/fn-item-type.rs:29:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
    |                       ^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
    |
    = note: expected fn item `fn(_) -> _ {bar::<std::string::String>}`
               found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar::<std::string::String> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:30:26
+  --> $DIR/fn-item-type.rs:39:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
    |                          ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
               found fn item `fn() {<u16 as Foo>::foo}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn()`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> $DIR/fn-item-type.rs:46:19
+   |
+LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+   |
+   = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+           found fn pointer `fn(_) -> _`
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 63c435cc20641268f130505e19e93e44ca463749..32660fdb41876158f95f34860e837cefd8c052cc 100644 (file)
@@ -29,3 +29,7 @@ fn main() {
     foo::<C>(); //~ ERROR: cannot find type `C` in this scope
     foo::<D>(); //~ ERROR: cannot find type `D` in this scope
 }
+
+mod other {
+    pub fn import() {}
+}
index 995da6cc1f97591ed07fcd348edd2865d8082f9b..3c818f3ae48ea4634db7720946b065247e97b3a5 100644 (file)
@@ -42,6 +42,11 @@ error[E0425]: cannot find function `import` in this scope
    |
 LL |     import();
    |     ^^^^^^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL | use other::import;
+   |
 
 error[E0412]: cannot find type `A` in this scope
   --> $DIR/glob-resolve1.rs:28:11
diff --git a/src/test/ui/impl-trait/issue-69840.rs b/src/test/ui/impl-trait/issue-69840.rs
new file mode 100644 (file)
index 0000000..b270f88
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(impl_trait_in_bindings)]
+#![allow(incomplete_features)]
+
+struct A<'a>(&'a ());
+
+trait Trait<T> {}
+
+impl<T> Trait<T> for () {}
+
+pub fn foo<'a>() {
+    let _x: impl Trait<A<'a>> = ();
+}
+
+fn main() {}
index 6f53680f7c81dc4e1261c9e1c853b87d9f7f7b89..9fee01c1ba62329789f91af0e17a8c080203df7d 100644 (file)
@@ -1,9 +1,3 @@
-//
-// We get an error message at the top of file (dummy span).
-// This is not helpful, but also kind of annoying to prevent,
-// so for now just live with it.
-// This test case was originally for issue #2258.
-
 // build-fail
 
 trait ToOpt: Sized {
@@ -23,11 +17,9 @@ fn to_option(&self) -> Option<Option<T>> {
 }
 
 fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-//~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
     if counter > 0 {
         function(counter - 1, t.to_option());
-        // FIXME(#4287) Error message should be here. It should be
-        // a type error to instantiate `test` at a type other than T.
+        //~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
     }
 }
 
index ae81c680a7b65f3e2853690e9e67e9d0c601692f..7b22393ee7c0f7a7ee856a87c1dbd9d35fd83fca 100644 (file)
@@ -1,11 +1,16 @@
 error: reached the recursion limit while instantiating `function::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<usize>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
-  --> $DIR/infinite-instantiation.rs:25:1
+  --> $DIR/infinite-instantiation.rs:21:9
+   |
+LL |         function(counter - 1, t.to_option());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `function` defined here
+  --> $DIR/infinite-instantiation.rs:19:1
    |
 LL | / fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-LL | |
 LL | |     if counter > 0 {
 LL | |         function(counter - 1, t.to_option());
-...  |
+LL | |
 LL | |     }
 LL | | }
    | |_^
index bae3813f9da951b01997de7073d3c21c9837d694..bafa204e06b252eb709c8cd936b12b3ab9cc1e80 100644 (file)
@@ -5,6 +5,7 @@
 struct Empty;
 
 // This used to cause an ICE
+#[allow(improper_ctypes_definitions)]
 extern "C" fn ice(_a: Empty) {}
 
 fn main() {
index f6d349a38f52338729d6880a785d64298c3f5720..fcabd1d84557c70abe60cf8b02cd55ac5e228e4e 100644 (file)
@@ -6,6 +6,7 @@ pub struct Foo {
 }
 
 impl Foo {
+    #[allow(improper_ctypes_definitions)]
     pub extern fn foo_new() -> Foo {
         Foo { x: 21, y: 33 }
     }
index 3bbe4ae29bdd69a45bf47919d3978eda55096291..297519b9a79e2b633384523a7db36b868f24315c 100644 (file)
@@ -6,6 +6,7 @@
 impl Test {
     #[allow(dead_code)]
     #[allow(unused_variables)]
+    #[allow(improper_ctypes_definitions)]
     pub extern fn test(val: &str) {
 
     }
index 6e6de09225f571f8391b37ab45e191c4f813411f..a966cf217e1655cc6f0a66ca1ea121647f23901f 100644 (file)
@@ -5,6 +5,7 @@
 pub struct Foo(i128);
 
 #[no_mangle]
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn foo(x: Foo) -> Foo { x }
 
 fn main() {
index 3691fe19117746649fa1fa33fdf88c16a8e207f9..52d26d0954af894a155a16d888c774b60f15a7b4 100644 (file)
@@ -6,7 +6,9 @@ trait Foo {
 
 struct Bar;
 impl Foo for Bar {
+    #[allow(improper_ctypes_definitions)]
     extern fn borrow(&self) {}
+    #[allow(improper_ctypes_definitions)]
     extern fn take(self: Box<Self>) {}
 }
 
index 1400c6f97b60509f31e419574d63a1e642c5168f..b0fcb74764b987b8e3f2fe1160cf4d1d2ee48a9e 100644 (file)
@@ -18,7 +18,6 @@ fn identity<T>(x: T) -> T {
 }
 
 fn rec<T>(mut it: T)
-//~^ ERROR reached the recursion limit while instantiating
 where
     T: Iterator,
 {
@@ -26,5 +25,6 @@ fn rec<T>(mut it: T)
         T::count(it);
     } else {
         rec(identity(&mut it))
+        //~^ ERROR reached the recursion limit while instantiating
     }
 }
index 881f9d221d6aedf9bf2cb4e8a2c710da3ba2f56e..3bb2016f07d24f03fc2f609343be749f589e3408 100644 (file)
@@ -1,10 +1,16 @@
 error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>`
+  --> $DIR/issue-67552.rs:27:9
+   |
+LL |         rec(identity(&mut it))
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `rec` defined here
   --> $DIR/issue-67552.rs:20:1
    |
 LL | / fn rec<T>(mut it: T)
-LL | |
 LL | | where
 LL | |     T: Iterator,
+LL | | {
 ...  |
 LL | |     }
 LL | | }
index 80f360155cb49f272b08c2d6f44c946a7f8fac71..14bdd8511119e0fdda184fb679c9d44925c5218c 100644 (file)
@@ -3,12 +3,10 @@
 
 // build-fail
 
-fn generic<T>() {
+fn generic<T>() { //~ WARN function cannot return without recursing
     generic::<Option<T>>();
 }
-//~^^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
-//~| WARN function cannot return without recursing
-
+//~^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
 
 
 fn main () {
index ee0672c598d5c10a177cc3fff6769766f157061e..70709fd33ac3ac170f287fbeaaf70ce118c59c2f 100644 (file)
@@ -10,6 +10,12 @@ LL |     generic::<Option<T>>();
    = help: a `loop` may express intention better if this is on purpose
 
 error: reached the recursion limit while instantiating `generic::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+  --> $DIR/issue-8727.rs:7:5
+   |
+LL |     generic::<Option<T>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `generic` defined here
   --> $DIR/issue-8727.rs:6:1
    |
 LL | / fn generic<T>() {
diff --git a/src/test/ui/lint/lint-ctypes-fn.rs b/src/test/ui/lint/lint-ctypes-fn.rs
new file mode 100644 (file)
index 0000000..67dd7ab
--- /dev/null
@@ -0,0 +1,182 @@
+#![feature(rustc_private)]
+
+#![allow(private_in_public)]
+#![deny(improper_ctypes_definitions)]
+
+extern crate libc;
+
+use std::default::Default;
+use std::marker::PhantomData;
+
+trait Mirror { type It: ?Sized; }
+
+impl<T: ?Sized> Mirror for T { type It = Self; }
+
+#[repr(C)]
+pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
+
+#[repr(C)]
+pub struct StructWithProjectionAndLifetime<'a>(
+    &'a mut <StructWithProjectionAndLifetime<'a> as Mirror>::It
+);
+
+pub type I32Pair = (i32, i32);
+
+#[repr(C)]
+pub struct ZeroSize;
+
+pub type RustFn = fn();
+
+pub type RustBadRet = extern fn() -> Box<u32>;
+
+pub type CVoidRet = ();
+
+pub struct Foo;
+
+#[repr(transparent)]
+pub struct TransparentI128(i128);
+
+#[repr(transparent)]
+pub struct TransparentStr(&'static str);
+
+#[repr(transparent)]
+pub struct TransparentBadFn(RustBadRet);
+
+#[repr(transparent)]
+pub struct TransparentInt(u32);
+
+#[repr(transparent)]
+pub struct TransparentRef<'a>(&'a TransparentInt);
+
+#[repr(transparent)]
+pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
+
+#[repr(transparent)]
+pub struct TransparentUnit<U>(f32, PhantomData<U>);
+
+#[repr(transparent)]
+pub struct TransparentCustomZst(i32, ZeroSize);
+
+#[repr(C)]
+pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
+
+pub extern "C" fn ptr_type1(size: *const Foo) { }
+
+pub extern "C" fn ptr_type2(size: *const Foo) { }
+
+pub extern "C" fn slice_type(p: &[u32]) { }
+//~^ ERROR: uses type `[u32]`
+
+pub extern "C" fn str_type(p: &str) { }
+//~^ ERROR: uses type `str`
+
+pub extern "C" fn box_type(p: Box<u32>) { }
+//~^ ERROR uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn char_type(p: char) { }
+//~^ ERROR uses type `char`
+
+pub extern "C" fn i128_type(p: i128) { }
+//~^ ERROR uses type `i128`
+
+pub extern "C" fn u128_type(p: u128) { }
+//~^ ERROR uses type `u128`
+
+pub extern "C" fn tuple_type(p: (i32, i32)) { }
+//~^ ERROR uses type `(i32, i32)`
+
+pub extern "C" fn tuple_type2(p: I32Pair) { }
+//~^ ERROR uses type `(i32, i32)`
+
+pub extern "C" fn zero_size(p: ZeroSize) { }
+//~^ ERROR uses type `ZeroSize`
+
+pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
+//~^ ERROR uses type `ZeroSizeWithPhantomData`
+
+pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
+//~^ ERROR uses type `std::marker::PhantomData<bool>`
+    Default::default()
+}
+
+pub extern "C" fn fn_type(p: RustFn) { }
+//~^ ERROR uses type `fn()`
+
+pub extern "C" fn fn_type2(p: fn()) { }
+//~^ ERROR uses type `fn()`
+
+pub extern "C" fn fn_contained(p: RustBadRet) { }
+//~^ ERROR: uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn transparent_i128(p: TransparentI128) { }
+//~^ ERROR: uses type `i128`
+
+pub extern "C" fn transparent_str(p: TransparentStr) { }
+//~^ ERROR: uses type `str`
+
+pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
+//~^ ERROR: uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn good3(fptr: Option<extern fn()>) { }
+
+pub extern "C" fn good4(aptr: &[u8; 4 as usize]) { }
+
+pub extern "C" fn good5(s: StructWithProjection) { }
+
+pub extern "C" fn good6(s: StructWithProjectionAndLifetime) { }
+
+pub extern "C" fn good7(fptr: extern fn() -> ()) { }
+
+pub extern "C" fn good8(fptr: extern fn() -> !) { }
+
+pub extern "C" fn good9() -> () { }
+
+pub extern "C" fn good10() -> CVoidRet { }
+
+pub extern "C" fn good11(size: isize) { }
+
+pub extern "C" fn good12(size: usize) { }
+
+pub extern "C" fn good13(n: TransparentInt) { }
+
+pub extern "C" fn good14(p: TransparentRef) { }
+
+pub extern "C" fn good15(p: TransparentLifetime) { }
+
+pub extern "C" fn good16(p: TransparentUnit<ZeroSize>) { }
+
+pub extern "C" fn good17(p: TransparentCustomZst) { }
+
+#[allow(improper_ctypes_definitions)]
+pub extern "C" fn good18(_: &String) { }
+
+#[cfg(not(target_arch = "wasm32"))]
+pub extern "C" fn good1(size: *const libc::c_int) { }
+
+#[cfg(not(target_arch = "wasm32"))]
+pub extern "C" fn good2(size: *const libc::c_uint) { }
+
+pub extern "C" fn unused_generic1<T>(size: *const Foo) { }
+
+pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
+//~^ ERROR uses type `std::marker::PhantomData<bool>`
+    Default::default()
+}
+
+pub extern "C" fn used_generic1<T>(x: T) { }
+
+pub extern "C" fn used_generic2<T>(x: T, size: *const Foo) { }
+
+pub extern "C" fn used_generic3<T: Default>() -> T {
+    Default::default()
+}
+
+pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
+//~^ ERROR: uses type `std::vec::Vec<T>`
+
+pub extern "C" fn used_generic5<T>() -> Vec<T> {
+//~^ ERROR: uses type `std::vec::Vec<T>`
+    Default::default()
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr
new file mode 100644 (file)
index 0000000..66cf195
--- /dev/null
@@ -0,0 +1,191 @@
+error: `extern` fn uses type `[u32]`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:67:33
+   |
+LL | pub extern "C" fn slice_type(p: &[u32]) { }
+   |                                 ^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-fn.rs:4:9
+   |
+LL | #![deny(improper_ctypes_definitions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
+
+error: `extern` fn uses type `str`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:70:31
+   |
+LL | pub extern "C" fn str_type(p: &str) { }
+   |                               ^^^^ not FFI-safe
+   |
+   = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:73:31
+   |
+LL | pub extern "C" fn box_type(p: Box<u32>) { }
+   |                               ^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `char`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:76:32
+   |
+LL | pub extern "C" fn char_type(p: char) { }
+   |                                ^^^^ not FFI-safe
+   |
+   = help: consider using `u32` or `libc::wchar_t` instead
+   = note: the `char` type has no C equivalent
+
+error: `extern` fn uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:79:32
+   |
+LL | pub extern "C" fn i128_type(p: i128) { }
+   |                                ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `u128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:82:32
+   |
+LL | pub extern "C" fn u128_type(p: u128) { }
+   |                                ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:85:33
+   |
+LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
+   |                                 ^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider using a struct instead
+   = note: tuples have unspecified layout
+
+error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:88:34
+   |
+LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
+   |                                  ^^^^^^^ not FFI-safe
+   |
+   = help: consider using a struct instead
+   = note: tuples have unspecified layout
+
+error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:91:32
+   |
+LL | pub extern "C" fn zero_size(p: ZeroSize) { }
+   |                                ^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a member to this struct
+   = note: this struct has no fields
+note: the type is defined here
+  --> $DIR/lint-ctypes-fn.rs:26:1
+   |
+LL | pub struct ZeroSize;
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:94:40
+   |
+LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
+note: the type is defined here
+  --> $DIR/lint-ctypes-fn.rs:61:1
+   |
+LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:97:51
+   |
+LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
+   |                                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
+
+error: `extern` fn uses type `fn()`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:102:30
+   |
+LL | pub extern "C" fn fn_type(p: RustFn) { }
+   |                              ^^^^^^ not FFI-safe
+   |
+   = help: consider using an `extern fn(...) -> ...` function pointer instead
+   = note: this function pointer has Rust-specific calling convention
+
+error: `extern` fn uses type `fn()`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:105:31
+   |
+LL | pub extern "C" fn fn_type2(p: fn()) { }
+   |                               ^^^^ not FFI-safe
+   |
+   = help: consider using an `extern fn(...) -> ...` function pointer instead
+   = note: this function pointer has Rust-specific calling convention
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:108:35
+   |
+LL | pub extern "C" fn fn_contained(p: RustBadRet) { }
+   |                                   ^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:111:39
+   |
+LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
+   |                                       ^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `str`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:114:38
+   |
+LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
+   |                                      ^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:117:37
+   |
+LL | pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
+   |                                     ^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:161:43
+   |
+LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
+   |                                           ^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
+
+error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:174:39
+   |
+LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
+   |                                       ^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:177:41
+   |
+LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
+   |                                         ^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: aborting due to 20 previous errors
+
index 12093837d2630bcb8387a60a63cef752e8c02b6d..e15ed2e70b896fa2b497e2c0cdef2ef34dd7889d 100644 (file)
@@ -2,8 +2,14 @@
 #![deny(confusable_idents)]
 #![allow(uncommon_codepoints, non_upper_case_globals)]
 
-const s: usize = 42; //~ ERROR identifier pair considered confusable
+const s: usize = 42;
 
 fn main() {
-    let s = "rust";
+    let s = "rust"; //~ ERROR identifier pair considered confusable
+    not_affected();
+}
+
+fn not_affected() {
+    let s1 = 1;
+    let sl = 'l';
 }
index 40ee18acb3cd4c68e426ebdc3f35654827844d45..218f94f7b5829483beb10155f6a0fbc223693043 100644 (file)
@@ -1,11 +1,11 @@
-error: identifier pair considered confusable between `s` and `s`
-  --> $DIR/lint-confusable-idents.rs:5:7
+error: identifier pair considered confusable between `s` and `s`
+  --> $DIR/lint-confusable-idents.rs:8:9
    |
 LL | const s: usize = 42;
-   |       ^^
+   |       -- this is where the previous identifier occurred
 ...
 LL |     let s = "rust";
-   |         - this is where the previous identifier occurred
+   |         ^
    |
 note: the lint level is defined here
   --> $DIR/lint-confusable-idents.rs:2:9
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs
new file mode 100644 (file)
index 0000000..a5b4546
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+#![feature(non_ascii_idents)]
+#![deny(mixed_script_confusables)]
+
+struct ΑctuallyNotLatin;
+
+fn main() {
+    let λ = 42; // this usage of Greek confirms that Greek is used intentionally.
+}
+
+mod роре {
+    const エ: &'static str = "アイウ";
+
+    // this usage of Katakana confirms that Katakana is used intentionally.
+    fn ニャン() {
+        let д: usize = 100; // this usage of Cyrillic confirms that Cyrillic is used intentionally.
+
+        println!("meow!");
+    }
+}
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs
new file mode 100644 (file)
index 0000000..4637b03
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(non_ascii_idents)]
+#![deny(mixed_script_confusables)]
+
+struct ΑctuallyNotLatin;
+//~^ ERROR The usage of Script Group `Greek` in this crate consists solely of
+
+fn main() {
+    let v = ΑctuallyNotLatin;
+}
+
+mod роре {
+//~^ ERROR The usage of Script Group `Cyrillic` in this crate consists solely of
+    const エ: &'static str = "アイウ";
+    //~^ ERROR The usage of Script Group `Japanese, Katakana` in this crate consists solely of
+}
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr
new file mode 100644 (file)
index 0000000..6f75a1e
--- /dev/null
@@ -0,0 +1,34 @@
+error: The usage of Script Group `Greek` in this crate consists solely of mixed script confusables
+  --> $DIR/lint-mixed-script-confusables.rs:4:8
+   |
+LL | struct ΑctuallyNotLatin;
+   |        ^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-mixed-script-confusables.rs:2:9
+   |
+LL | #![deny(mixed_script_confusables)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: The usage includes 'Α' (U+0391).
+   = note: Please recheck to make sure their usages are indeed what you want.
+
+error: The usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables
+  --> $DIR/lint-mixed-script-confusables.rs:11:5
+   |
+LL | mod роре {
+   |     ^^^^
+   |
+   = note: The usage includes 'е' (U+0435), 'о' (U+043E), 'р' (U+0440).
+   = note: Please recheck to make sure their usages are indeed what you want.
+
+error: The usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables
+  --> $DIR/lint-mixed-script-confusables.rs:13:11
+   |
+LL |     const エ: &'static str = "アイウ";
+   |           ^^
+   |
+   = note: The usage includes 'エ' (U+30A8).
+   = note: Please recheck to make sure their usages are indeed what you want.
+
+error: aborting due to 3 previous errors
+
index 057329a0a650cfc061bd3d0103ce9d5c64df9ac0..20d00cf701a1569fe5f33ef0b0d0fdbcdc3900a1 100644 (file)
@@ -7,5 +7,7 @@ fn coöperation() {} //~ ERROR identifier contains non-ASCII characters
 
 fn main() {
     let naïveté = 2; //~ ERROR identifier contains non-ASCII characters
-    println!("{}", naïveté); //~ ERROR identifier contains non-ASCII characters
+
+    // using the same identifier the second time won't trigger the lint.
+    println!("{}", naïveté);
 }
index 6c9f0866c017a59102d903b821c9659af2cb1400..048b6ff5d687f011dac0ac01991bf589e4821f70 100644 (file)
@@ -22,11 +22,5 @@ error: identifier contains non-ASCII characters
 LL |     let naïveté = 2;
    |         ^^^^^^^
 
-error: identifier contains non-ASCII characters
-  --> $DIR/lint-non-ascii-idents.rs:10:20
-   |
-LL |     println!("{}", naïveté);
-   |                    ^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
index 7ac0d035d5bf1eb146367728ef84c92103f91bdc..b5e251e047b5ad1f8ca37054603d4b1fb9577185 100644 (file)
@@ -7,5 +7,7 @@ fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints
 
 fn main() {
     let ㇻㇲㇳ = "rust"; //~ ERROR identifier contains uncommon Unicode codepoints
-    println!("{}", ㇻㇲㇳ); //~ ERROR identifier contains uncommon Unicode codepoints
+
+    // using the same identifier the second time won't trigger the lint.
+    println!("{}", ㇻㇲㇳ);
 }
index b270bd1f051c261894ee5dd3636c9964ddf8718f..05ea3d5de7dbc9759ec0482fd006d8fbad544a7c 100644 (file)
@@ -22,11 +22,5 @@ error: identifier contains uncommon Unicode codepoints
 LL |     let ㇻㇲㇳ = "rust";
    |         ^^^^^^
 
-error: identifier contains uncommon Unicode codepoints
-  --> $DIR/lint-uncommon-codepoints.rs:10:20
-   |
-LL |     println!("{}", ㇻㇲㇳ);
-   |                    ^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
index 69fd64c1c092c262e52dfa631a3889d9036fdaef..4574dbd8529aa56a88c29ee278e3355df2dd176e 100644 (file)
@@ -1,8 +1,10 @@
 // run-pass
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn tuple2() -> (u16, u8) {
     (1, 2)
 }
 
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn tuple3() -> (u8, u8, u8) {
     (1, 2, 3)
 }
index fc0db03e3a96894350a9611f398c150de1afebe3..d93a25c8ef4d372148b92ce6e6c2ed0b8031bd04 100644 (file)
@@ -74,6 +74,7 @@ fn test8() -> isize {
     Two::two()
 }
 
+#[allow(improper_ctypes_definitions)]
 extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
     x + y.0 * y.1
 }
index 0940dbe6a5e87bc2de526500c0a2aea0462974f4..136c03cd9f1bcad4a1b1062f2fdc44515f81ffba 100644 (file)
@@ -19,6 +19,6 @@ fn mod_by_zero() {
 fn oob_error_for_slices() {
     let a: *const [_] = &[1, 2, 3];
     unsafe {
-        let _b = (*a)[3]; //~ ERROR this operation will panic at runtime [unconditional_panic]
+        let _b = (*a)[3];
     }
 }
index 41f03789f237f62cf0b260d3b9a4613e07c1c18e..0b6dbfd7c3d85f61c00c4f8aad2a1c3ac1c896fb 100644 (file)
@@ -12,11 +12,5 @@ error: this operation will panic at runtime
 LL |     let _z = 1 % y;
    |              ^^^^^ attempt to calculate the remainder with a divisor of zero
 
-error: this operation will panic at runtime
-  --> $DIR/mir_detects_invalid_ops.rs:22:18
-   |
-LL |         let _b = (*a)[3];
-   |                  ^^^^^^^ index out of bounds: the len is 3 but the index is 3
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
index c80055f00d7d9ecafee88a26261870d34491caaa..ee730910ee44153be90e0c503aaa40b825cfacd0 100644 (file)
@@ -16,7 +16,7 @@ help: consider importing one of these items instead
    |
 LL | use m2::S;
    |
-LL | use namespace_mix::xm2::S;
+LL | use xm2::S;
    |
 
 error[E0423]: expected value, found type alias `xm1::S`
@@ -39,7 +39,7 @@ help: consider importing one of these items instead
    |
 LL | use m2::S;
    |
-LL | use namespace_mix::xm2::S;
+LL | use xm2::S;
    |
 
 error[E0423]: expected value, found struct variant `m7::V`
@@ -61,7 +61,7 @@ help: consider importing one of these items instead
    |
 LL | use m8::V;
    |
-LL | use namespace_mix::xm8::V;
+LL | use xm8::V;
    |
 
 error[E0423]: expected value, found struct variant `xm7::V`
@@ -83,7 +83,7 @@ help: consider importing one of these items instead
    |
 LL | use m8::V;
    |
-LL | use namespace_mix::xm8::V;
+LL | use xm8::V;
    |
 
 error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
diff --git a/src/test/ui/never_type/issue-51506.rs b/src/test/ui/never_type/issue-51506.rs
new file mode 100644 (file)
index 0000000..d0fe6a0
--- /dev/null
@@ -0,0 +1,41 @@
+#![feature(never_type, specialization)]
+#![allow(incomplete_features)]
+
+use std::iter::{self, Empty};
+
+trait Trait {
+    type Out: Iterator<Item = u32>;
+
+    fn f(&self) -> Option<Self::Out>;
+}
+
+impl<T> Trait for T {
+    default type Out = !; //~ ERROR: `!` is not an iterator
+
+    default fn f(&self) -> Option<Self::Out> {
+        None
+    }
+}
+
+struct X;
+
+impl Trait for X {
+    type Out = Empty<u32>;
+
+    fn f(&self) -> Option<Self::Out> {
+        Some(iter::empty())
+    }
+}
+
+fn f<T: Trait>(a: T) {
+    if let Some(iter) = a.f() {
+        println!("Some");
+        for x in iter {
+            println!("x = {}", x);
+        }
+    }
+}
+
+pub fn main() {
+    f(10);
+}
diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr
new file mode 100644 (file)
index 0000000..73865a9
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0277]: `!` is not an iterator
+  --> $DIR/issue-51506.rs:13:5
+   |
+LL |     type Out: Iterator<Item = u32>;
+   |     ------------------------------- required by `Trait::Out`
+...
+LL |     default type Out = !;
+   |     ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `!`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 57de4b87b0fe6bbbada21a4dd7fe1b5755f8eff0..5259dfe2e656c9f255920434c7706e45a00799ae 100644 (file)
@@ -1,4 +1,6 @@
 // ignore-tidy-trailing-newlines
 // error-pattern: aborting due to 3 previous errors
+#![allow(uncommon_codepoints)]
+
 y![
 Ϥ,
\ No newline at end of file
index 8191c9682cefd8f597d5f61b2deae9de426cc9d4..d5e07622b11b99dce7867a65762ed90655b5d692 100644 (file)
@@ -1,5 +1,5 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/issue-62524.rs:4:3
+  --> $DIR/issue-62524.rs:6:3
    |
 LL | y![
    |   - unclosed delimiter
@@ -7,7 +7,7 @@ LL | Ϥ,
    |   ^
 
 error: macros that expand to items must be delimited with braces or followed by a semicolon
-  --> $DIR/issue-62524.rs:3:3
+  --> $DIR/issue-62524.rs:5:3
    |
 LL |   y![
    |  ___^
@@ -24,7 +24,7 @@ LL | Ϥ,;
    |   ^
 
 error: cannot find macro `y` in this scope
-  --> $DIR/issue-62524.rs:3:1
+  --> $DIR/issue-62524.rs:5:1
    |
 LL | y![
    | ^
diff --git a/src/test/ui/proc-macro/auxiliary/first-second.rs b/src/test/ui/proc-macro/auxiliary/first-second.rs
new file mode 100644 (file)
index 0000000..6331608
--- /dev/null
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group, Delimiter};
+
+#[proc_macro_attribute]
+pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    let tokens: TokenStream = "#[derive(Second)]".parse().unwrap();
+    let wrapped = TokenTree::Group(Group::new(Delimiter::None, item.into_iter().collect()));
+    tokens.into_iter().chain(std::iter::once(wrapped)).collect()
+}
+
+#[proc_macro_derive(Second)]
+pub fn second(item: TokenStream) -> TokenStream {
+    TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/recollect.rs b/src/test/ui/proc-macro/auxiliary/recollect.rs
new file mode 100644 (file)
index 0000000..d4494a5
--- /dev/null
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn recollect(tokens: TokenStream) -> TokenStream {
+    tokens.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/weird-hygiene.rs b/src/test/ui/proc-macro/auxiliary/weird-hygiene.rs
new file mode 100644 (file)
index 0000000..338e436
--- /dev/null
@@ -0,0 +1,48 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group};
+
+fn find_my_ident(tokens: TokenStream) -> Option<TokenStream> {
+    for token in tokens {
+        if let TokenTree::Ident(ident) = &token {
+            if ident.to_string() == "hidden_ident" {
+                return Some(vec![token].into_iter().collect())
+            }
+        } else if let TokenTree::Group(g) = token {
+            if let Some(stream) = find_my_ident(g.stream()) {
+                return Some(stream)
+            }
+        }
+    }
+    return None;
+}
+
+
+#[proc_macro_derive(WeirdDerive)]
+pub fn weird_derive(item: TokenStream) -> TokenStream {
+    let my_ident = find_my_ident(item).expect("Missing 'my_ident'!");
+    let tokens: TokenStream = "call_it!();".parse().unwrap();
+    let final_call = tokens.into_iter().map(|tree| {
+        if let TokenTree::Group(g) = tree {
+            return Group::new(g.delimiter(), my_ident.clone()).into()
+        } else {
+            return tree
+        }
+    }).collect();
+    final_call
+}
+
+#[proc_macro]
+pub fn recollect(item: TokenStream) -> TokenStream {
+    item.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn recollect_attr(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
+    item.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs
new file mode 100644 (file)
index 0000000..a404dda
--- /dev/null
@@ -0,0 +1,22 @@
+// aux-build:test-macros.rs
+// check-pass
+
+extern crate test_macros;
+use test_macros::recollect;
+
+macro_rules! use_expr {
+    ($expr:expr) => {
+        recollect!($expr)
+    }
+}
+
+#[allow(dead_code)]
+struct Foo;
+impl Foo {
+    #[allow(dead_code)]
+    fn use_self(self) {
+        drop(use_expr!(self));
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/macro-rules-derive.rs b/src/test/ui/proc-macro/macro-rules-derive.rs
new file mode 100644 (file)
index 0000000..5b4d577
--- /dev/null
@@ -0,0 +1,20 @@
+// aux-build:first-second.rs
+// FIXME: The spans here are bad, see PR #73084
+
+extern crate first_second;
+use first_second::*;
+
+macro_rules! produce_it {
+    ($name:ident) => {
+        #[first] //~ ERROR cannot find type
+        struct $name {
+            field: MissingType
+        }
+    }
+}
+
+produce_it!(MyName);
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/proc-macro/macro-rules-derive.stderr b/src/test/ui/proc-macro/macro-rules-derive.stderr
new file mode 100644 (file)
index 0000000..4b72d29
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `MissingType` in this scope
+  --> $DIR/macro-rules-derive.rs:9:9
+   |
+LL |         #[first]
+   |         ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/proc-macro/weird-hygiene.rs b/src/test/ui/proc-macro/weird-hygiene.rs
new file mode 100644 (file)
index 0000000..3f48191
--- /dev/null
@@ -0,0 +1,48 @@
+// aux-build:weird-hygiene.rs
+// check-pass
+// FIXME: This should actually error, see PR #73084
+
+#![feature(stmt_expr_attributes)]
+#![feature(proc_macro_hygiene)]
+
+extern crate weird_hygiene;
+use weird_hygiene::*;
+
+macro_rules! other {
+    ($tokens:expr) => {
+        macro_rules! call_it {
+            ($outer_ident:ident) => {
+                macro_rules! inner {
+                    () => {
+                        $outer_ident;
+                    }
+                }
+            }
+        }
+
+        #[derive(WeirdDerive)]
+        enum MyEnum {
+            Value = (stringify!($tokens + hidden_ident), 1).1
+        }
+
+        inner!();
+    }
+}
+
+macro_rules! invoke_it {
+    ($token:expr) => {
+        #[recollect_attr] {
+            $token;
+            hidden_ident
+        }
+    }
+}
+
+fn main() {
+    // `other` and `invoke_it` are both macro_rules! macros,
+    // so it should be impossible for them to ever see `hidden_ident`,
+    // even if they invoke a proc macro.
+    let hidden_ident = "Hello1";
+    other!(50);
+    invoke_it!(25);
+}
diff --git a/src/test/ui/range/issue-73553-misinterp-range-literal.rs b/src/test/ui/range/issue-73553-misinterp-range-literal.rs
new file mode 100644 (file)
index 0000000..e65dba0
--- /dev/null
@@ -0,0 +1,16 @@
+type Range = std::ops::Range<usize>;
+
+fn demo(r: &Range) {
+    println!("{:?}", r);
+}
+
+fn tell(x: usize) -> usize {
+    x
+}
+
+fn main() {
+    demo(tell(1)..tell(10));
+    //~^ ERROR mismatched types
+    demo(1..10);
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/range/issue-73553-misinterp-range-literal.stderr b/src/test/ui/range/issue-73553-misinterp-range-literal.stderr
new file mode 100644 (file)
index 0000000..5167b87
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-73553-misinterp-range-literal.rs:12:10
+   |
+LL |     demo(tell(1)..tell(10));
+   |          ^^^^^^^^^^^^^^^^^
+   |          |
+   |          expected reference, found struct `std::ops::Range`
+   |          help: consider borrowing here: `&(tell(1)..tell(10))`
+   |
+   = note: expected reference `&std::ops::Range<usize>`
+                 found struct `std::ops::Range<usize>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-73553-misinterp-range-literal.rs:14:10
+   |
+LL |     demo(1..10);
+   |          ^^^^^
+   |          |
+   |          expected reference, found struct `std::ops::Range`
+   |          help: consider borrowing here: `&(1..10)`
+   |
+   = note: expected reference `&std::ops::Range<usize>`
+                 found struct `std::ops::Range<{integer}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index de6df4cd0268c1a7587115e2485d827c36f0454e..0552847c48ca9ac7b3ecaeac38d422e7e89b296c 100644 (file)
@@ -1,4 +1,22 @@
 error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::<S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>> - shim(Some(S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>))`
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | |     // Code here does not matter - this is replaced by the
+LL | |     // real drop glue by the compiler.
+LL | |     drop_in_place(to_drop)
+LL | | }
+   | |_^
+   |
+note: `std::intrinsics::drop_in_place` defined here
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | |     // Code here does not matter - this is replaced by the
+LL | |     // real drop glue by the compiler.
+LL | |     drop_in_place(to_drop)
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
index bf1eaef367d69d05b0ae4519fb5eda80fd6700f7..373cc17d0e0fe1c05ceccc17740f8e3733a13d9a 100644 (file)
@@ -12,11 +12,10 @@ fn dot(&self, other:Cons<T>) -> isize {
     self.head * other.head + self.tail.dot(other.tail)
   }
 }
-fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize { //~ ERROR recursion limit
+fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
   match n {    0 => {first.dot(second)}
-      // FIXME(#4287) Error message should be here. It should be
-      // a type error to instantiate `test` at a type other than T.
     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+    //~^ ERROR recursion limit
   }
 }
 pub fn main() {
index 1a65b0e84f6a3e399855166184b8e43b5f135bb6..0c0eba68c83b4d1ac7cd4181db93e553e0c9ca93 100644 (file)
@@ -1,11 +1,16 @@
 error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Nil>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+  --> $DIR/recursion.rs:17:11
+   |
+LL |     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `test` defined here
   --> $DIR/recursion.rs:15:1
    |
 LL | / fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
 LL | |   match n {    0 => {first.dot(second)}
-LL | |       // FIXME(#4287) Error message should be here. It should be
-LL | |       // a type error to instantiate `test` at a type other than T.
 LL | |     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+LL | |
 LL | |   }
 LL | | }
    | |_^
index f9263d2af5026993d80a4b10ea48caca218b4def..d4fd7cb1257e051469f95a879c2fd1ab4e1f7547 100644 (file)
@@ -4,7 +4,9 @@ error[E0405]: cannot find trait `T` in this scope
 LL | impl T for Foo { }
    |      ^ not found in this scope
    |
-help: consider importing this trait
+help: consider importing one of these items
+   |
+LL | use baz::T;
    |
 LL | use foo::bar::T;
    |
index d9b1b9c59558a7a1f48e55376bcb4cd0b27031ee..16baa6c9b623311e58b0b4b6168b412118466e8c 100644 (file)
@@ -132,7 +132,7 @@ LL |     let _: E = m::n::Z;
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0423]: expected value, found enum `m::n::Z`
@@ -165,7 +165,7 @@ LL |     let _: E = m::n::Z::Fn;
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0412]: cannot find type `Z` in this scope
@@ -183,7 +183,7 @@ LL |     let _: E = m::n::Z::Struct;
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0423]: expected value, found struct variant `m::n::Z::Struct`
@@ -212,7 +212,7 @@ LL |     let _: E = m::n::Z::Unit {};
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0603]: enum `Z` is private
diff --git a/src/test/ui/specialization/issue-44861.rs b/src/test/ui/specialization/issue-44861.rs
new file mode 100644 (file)
index 0000000..c37a627
--- /dev/null
@@ -0,0 +1,40 @@
+#![crate_type = "lib"]
+#![feature(specialization)]
+#![feature(unsize, coerce_unsized)]
+#![allow(incomplete_features)]
+
+use std::ops::CoerceUnsized;
+
+pub struct SmartassPtr<A: Smartass+?Sized>(A::Data);
+
+pub trait Smartass {
+    type Data;
+    type Data2: CoerceUnsized<*const [u8]>;
+}
+
+pub trait MaybeObjectSafe {}
+
+impl MaybeObjectSafe for () {}
+
+impl<T> Smartass for T {
+    type Data = <Self as Smartass>::Data2;
+    default type Data2 = ();
+    //~^ ERROR: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied
+}
+
+impl Smartass for () {
+    type Data2 = *const [u8; 1];
+}
+
+impl Smartass for dyn MaybeObjectSafe {
+    type Data = *const [u8];
+    type Data2 = *const [u8; 0];
+}
+
+impl<U: Smartass+?Sized, T: Smartass+?Sized> CoerceUnsized<SmartassPtr<T>> for SmartassPtr<U>
+    where <U as Smartass>::Data: std::ops::CoerceUnsized<<T as Smartass>::Data>
+{}
+
+pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeObjectSafe> {
+    s
+}
diff --git a/src/test/ui/specialization/issue-44861.stderr b/src/test/ui/specialization/issue-44861.stderr
new file mode 100644 (file)
index 0000000..b41b17e
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied
+  --> $DIR/issue-44861.rs:21:5
+   |
+LL |     type Data2: CoerceUnsized<*const [u8]>;
+   |     --------------------------------------- required by `Smartass::Data2`
+...
+LL |     default type Data2 = ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::CoerceUnsized<*const [u8]>` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/issue-59435.rs b/src/test/ui/specialization/issue-59435.rs
new file mode 100644 (file)
index 0000000..47323d3
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+struct MyStruct {}
+
+trait MyTrait {
+    type MyType: Default;
+}
+
+impl MyTrait for i32 {
+    default type MyType = MyStruct;
+    //~^ ERROR: the trait bound `MyStruct: std::default::Default` is not satisfied
+}
+
+fn main() {
+    let _x: <i32 as MyTrait>::MyType = <i32 as MyTrait>::MyType::default();
+}
diff --git a/src/test/ui/specialization/issue-59435.stderr b/src/test/ui/specialization/issue-59435.stderr
new file mode 100644 (file)
index 0000000..fd512a5
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `MyStruct: std::default::Default` is not satisfied
+  --> $DIR/issue-59435.rs:11:5
+   |
+LL |     type MyType: Default;
+   |     --------------------- required by `MyTrait::MyType`
+...
+LL |     default type MyType = MyStruct;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `MyStruct`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.rs b/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.rs
new file mode 100644 (file)
index 0000000..0cf77da
--- /dev/null
@@ -0,0 +1,58 @@
+// check-pass
+//
+// rust-lang/rust#73592: borrow_mut through Deref should work.
+//
+// Before #72280, when we see something like `&mut *rcvr.method()`, we
+// incorrectly requires `rcvr` to be type-checked as a mut place. While this
+// requirement is usually correct for smart pointers, it is overly restrictive
+// for types like `Mutex` or `RefCell` which can produce a guard that
+// implements `DerefMut` from `&self`.
+//
+// Making it more confusing, because we use Deref as the fallback when DerefMut
+// is implemented, we won't see an issue when the smart pointer does not
+// implement `DerefMut`. It only causes an issue when `rcvr` is obtained via a
+// type that implements both `Deref` or `DerefMut`.
+//
+// This bug is only discovered in #73592 after it is already fixed as a side-effect
+// of a refactoring made in #72280.
+
+#![warn(unused_mut)]
+
+use std::pin::Pin;
+use std::cell::RefCell;
+
+struct S(RefCell<()>);
+
+fn test_pin(s: Pin<&S>) {
+    // This works before #72280.
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_pin_mut(s: Pin<&mut S>) {
+    // This should compile but didn't before #72280.
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_vec(s: &Vec<RefCell<()>>) {
+    // This should compile but didn't before #72280.
+    let _ = &mut *s[0].borrow_mut();
+}
+
+fn test_mut_pin(mut s: Pin<&S>) {
+    //~^ WARN variable does not need to be mutable
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_mut_pin_mut(mut s: Pin<&mut S>) {
+    //~^ WARN variable does not need to be mutable
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn main() {
+    let mut s = S(RefCell::new(()));
+    test_pin(Pin::new(&s));
+    test_pin_mut(Pin::new(&mut s));
+    test_mut_pin(Pin::new(&s));
+    test_mut_pin_mut(Pin::new(&mut s));
+    test_vec(&vec![s.0]);
+}
diff --git a/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.stderr b/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.stderr
new file mode 100644 (file)
index 0000000..51303ad
--- /dev/null
@@ -0,0 +1,24 @@
+warning: variable does not need to be mutable
+  --> $DIR/issue-73592-borrow_mut-through-deref.rs:41:17
+   |
+LL | fn test_mut_pin(mut s: Pin<&S>) {
+   |                 ----^
+   |                 |
+   |                 help: remove this `mut`
+   |
+note: the lint level is defined here
+  --> $DIR/issue-73592-borrow_mut-through-deref.rs:19:9
+   |
+LL | #![warn(unused_mut)]
+   |         ^^^^^^^^^^
+
+warning: variable does not need to be mutable
+  --> $DIR/issue-73592-borrow_mut-through-deref.rs:46:21
+   |
+LL | fn test_mut_pin_mut(mut s: Pin<&mut S>) {
+   |                     ----^
+   |                     |
+   |                     help: remove this `mut`
+
+warning: 2 warnings emitted
+
index f59d5502aae30b3c98053b2e371ae910b87651a9..6c54086cc2009a4059218f16825fd85dde53da3f 100644 (file)
@@ -1,3 +1,5 @@
+#![allow(mixed_script_confusables)]
+
 fn foo<
     'β, //~ ERROR non-ascii idents are not fully supported
     γ  //~ ERROR non-ascii idents are not fully supported
index 877412df8fa1c8495d2a9f3cac74a5b8998441f9..2fc0b1c39effb54f6766d3f6f0b8cd413dbae562 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:2:5
+  --> $DIR/utf8_idents.rs:4:5
    |
 LL |     'β,
    |     ^^
@@ -8,7 +8,7 @@ LL |     'β,
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:3:5
+  --> $DIR/utf8_idents.rs:5:5
    |
 LL |     γ
    |     ^
@@ -17,7 +17,7 @@ LL |     γ
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:8:5
+  --> $DIR/utf8_idents.rs:10:5
    |
 LL |     δ: usize
    |     ^
@@ -26,7 +26,7 @@ LL |     δ: usize
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:12:9
+  --> $DIR/utf8_idents.rs:14:9
    |
 LL |     let α = 0.00001f64;
    |         ^
@@ -35,7 +35,7 @@ LL |     let α = 0.00001f64;
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 warning: type parameter `γ` should have an upper camel case name
-  --> $DIR/utf8_idents.rs:3:5
+  --> $DIR/utf8_idents.rs:5:5
    |
 LL |     γ
    |     ^ help: convert the identifier to upper camel case: `Γ`
index 39baa6b8540df7dc320df87c372019667097c63b..9eb43eb2df43fd7032fdccba9c2ad1635fe49aa2 100644 (file)
@@ -7,7 +7,6 @@
 #![deny(warnings)]
 
 use serde::Serialize;
-use toml;
 
 use std::collections::BTreeMap;
 use std::collections::HashMap;
index 089cbb80b73ba242efdcf5430e89f63fa3b5328d..c26576f9adddd254b3dd63aecba176434290a9f6 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 089cbb80b73ba242efdcf5430e89f63fa3b5328d
+Subproject commit c26576f9adddd254b3dd63aecba176434290a9f6
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE.md b/src/tools/clippy/.github/ISSUE_TEMPLATE.md
deleted file mode 100644 (file)
index 15006a0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<!--
-Hi there! Whether you've come to make a suggestion for a new lint, an improvement to an existing lint or to report a bug or a false positive in Clippy, you've come to the right place.
-
-For bug reports and false positives, please include the output of `cargo clippy -V` in the report.
-
-Thank you for using Clippy!
-
-Write your comment below this line: -->
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md
new file mode 100644 (file)
index 0000000..9aef3eb
--- /dev/null
@@ -0,0 +1,4 @@
+---
+name: Blank Issue
+about: Create a blank issue.
+---
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644 (file)
index 0000000..d8f0c44
--- /dev/null
@@ -0,0 +1,47 @@
+---
+name: Bug Report
+about: Create a bug report for Clippy
+labels: L-bug
+---
+<!--
+Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
+along with any information you feel relevant to replicating the bug.
+-->
+
+I tried this code:
+
+```rust
+<code>
+```
+
+I expected to see this happen: *explanation*
+
+Instead, this happened: *explanation*
+
+### Meta
+
+- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
+- `rustc -Vv`:
+  ```
+  rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+  binary: rustc
+  commit-hash: f455e46eae1a227d735091091144601b467e1565
+  commit-date: 2020-06-20
+  host: x86_64-unknown-linux-gnu
+  release: 1.46.0-nightly
+  LLVM version: 10.0
+  ```
+
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+-->
+<details><summary>Backtrace</summary>
+  <p>
+  
+  ```
+  <backtrace>
+  ```
+  
+  </p>
+</details>
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/config.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644 (file)
index 0000000..bd7dc0a
--- /dev/null
@@ -0,0 +1,5 @@
+blank_issues_enabled: true
+contact_links:
+  - name: Rust Programming Language Forum
+    url: https://users.rust-lang.org
+    about: Please ask and answer questions about Rust here.
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md
new file mode 100644 (file)
index 0000000..3abe76b
--- /dev/null
@@ -0,0 +1,53 @@
+---
+name: Internal Compiler Error
+about: Create a report for an internal compiler error in Clippy.
+labels: L-bug, L-crash
+---
+<!--
+Thank you for finding an Internal Compiler Error! 🧊  If possible, try to provide
+a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
+how to create smaller examples.
+
+http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
+
+-->
+
+### Code
+
+```rust
+<code>
+```
+
+### Meta
+
+- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
+- `rustc -Vv`:
+  ```
+  rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+  binary: rustc
+  commit-hash: f455e46eae1a227d735091091144601b467e1565
+  commit-date: 2020-06-20
+  host: x86_64-unknown-linux-gnu
+  release: 1.46.0-nightly
+  LLVM version: 10.0
+  ```
+
+### Error output
+
+```
+<output>
+```
+
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+-->
+<details><summary>Backtrace</summary>
+  <p>
+  
+  ```
+  <backtrace>
+  ```
+  
+  </p>
+</details>
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md
new file mode 100644 (file)
index 0000000..70445d7
--- /dev/null
@@ -0,0 +1,35 @@
+---
+name: New lint suggestion
+about: Suggest a new Clippy lint.
+labels: L-lint
+---
+
+### What it does
+
+*What does this lint do?*
+
+### Categories (optional)
+
+- Kind: *See <https://github.com/rust-lang/rust-clippy/blob/master/README.md#clippy> for list of lint kinds*
+
+*What benefit of this lint over old code?*
+
+For example:
+- Remove bounce checking inserted by ...
+- Remove the need to duplicating/storing/typo ...
+
+### Drawbacks
+
+None.
+
+### Example
+
+```rust
+<code>
+```
+
+Could be written as:
+
+```rust
+<code>
+```
index 97aa220afea540e16a4a18ff05b67fc030f136c4..137a73630940a4a69d2f77949fefc76ea177dcca 100644 (file)
@@ -28,4 +28,5 @@ Delete this line and everything above before opening your PR.
 
 ---
 
+*Please keep the line below*
 changelog: none
index a2e87f5eb3745837c4a71cc2dad41a3473677bd3..2c17c4203ae5c737e8005ae3454656e99619bd99 100644 (file)
@@ -26,4 +26,16 @@ unset CARGO_MANIFEST_DIR
 sed -e "s,tests/ui,\$DIR," -e "/= help/d" cstring.stderr > normalized.stderr
 diff normalized.stderr tests/ui/cstring.stderr
 
+
+# make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
+SYSROOT=`rustc --print sysroot`
+diff <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose)
+
+
+echo "fn main() {}" > target/driver_test.rs
+# we can't run 2 rustcs on the same file at the same time
+CLIPPY=`LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver ./target/driver_test.rs --rustc`
+RUSTC=`rustc ./target/driver_test.rs`
+diff <($CLIPPY) <($RUSTC)
+
 # TODO: CLIPPY_CONF_DIR / CARGO_MANIFEST_DIR
index 22c5acca064e9242b4f7c1f962ccd25044ba9d08..550752396c7324f7f857199be2c37c34844b605f 100644 (file)
@@ -396,7 +396,7 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
-            (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty(left).kind {
+            (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty_opt(left)?.kind {
                 ty::Int(ity) => {
                     let l = sext(self.lcx.tcx, l, ity);
                     let r = sext(self.lcx.tcx, r, ity);
index 59af475af175e2c484318fe1cbfb354965d3a9ea..77e90eeac49589ecfcdfcb1c9488f61dc54fe832 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_target::abi::LayoutOf;
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 use crate::utils::span_lint;
 
index 13e85fda8ffebb607bc7390db32c4bfed5274098..7838e8e8ab774c8d6e456fabb552e42e6faa0cf7 100644 (file)
@@ -211,7 +211,8 @@ fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef<'_>, name: &str) -
 }
 
 fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
+    {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
index 710dec8d33fc9e085d83582857e7698fb99389a7..acd628bbaca596b92ca4f34eed5df3c8bc6fb9fe 100644 (file)
@@ -35,7 +35,7 @@
     /// **What it does:** Checks for `let _ = sync_lock`
     ///
     /// **Why is this bad?** This statement immediately drops the lock instead of
-    /// extending it's lifetime to the end of the scope, which is often not intended.
+    /// extending its lifetime to the end of the scope, which is often not intended.
     /// To extend lock lifetime to the end of the scope, use an underscore-prefixed
     /// name instead (i.e. _lock). If you want to explicitly drop the lock,
     /// `std::mem::drop` conveys your intention better and is less error-prone.
index cd258c7b506c39ccd635b4560fd19004958b0d6e..501220f28e5db4d2fb57facf9825dcd142392432 100644 (file)
@@ -1,63 +1,44 @@
 // error-pattern:cargo-clippy
 
 #![feature(bindings_after_at)]
-#![feature(box_syntax)]
 #![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(concat_idents)]
+#![feature(crate_visibility_modifier)]
+#![feature(drain_filter)]
 #![feature(or_patterns)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
-#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
 #![recursion_limit = "512"]
-#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
-#![deny(rustc::internal)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
-#![feature(crate_visibility_modifier)]
-#![feature(concat_idents)]
-#![feature(drain_filter)]
+#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
+#![warn(trivial_casts, trivial_numeric_casts)]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![deny(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
-#[allow(unused_extern_crates)]
 extern crate rustc_ast;
-#[allow(unused_extern_crates)]
 extern crate rustc_ast_pretty;
-#[allow(unused_extern_crates)]
 extern crate rustc_attr;
-#[allow(unused_extern_crates)]
 extern crate rustc_data_structures;
-#[allow(unused_extern_crates)]
-extern crate rustc_driver;
-#[allow(unused_extern_crates)]
 extern crate rustc_errors;
-#[allow(unused_extern_crates)]
 extern crate rustc_hir;
-#[allow(unused_extern_crates)]
 extern crate rustc_hir_pretty;
-#[allow(unused_extern_crates)]
 extern crate rustc_index;
-#[allow(unused_extern_crates)]
 extern crate rustc_infer;
-#[allow(unused_extern_crates)]
 extern crate rustc_lexer;
-#[allow(unused_extern_crates)]
 extern crate rustc_lint;
-#[allow(unused_extern_crates)]
 extern crate rustc_middle;
-#[allow(unused_extern_crates)]
 extern crate rustc_mir;
-#[allow(unused_extern_crates)]
 extern crate rustc_parse;
-#[allow(unused_extern_crates)]
 extern crate rustc_parse_format;
-#[allow(unused_extern_crates)]
 extern crate rustc_session;
-#[allow(unused_extern_crates)]
 extern crate rustc_span;
-#[allow(unused_extern_crates)]
 extern crate rustc_target;
-#[allow(unused_extern_crates)]
 extern crate rustc_trait_selection;
-#[allow(unused_extern_crates)]
 extern crate rustc_typeck;
 
 use rustc_data_structures::fx::FxHashSet;
 /// # Example
 ///
 /// ```
-/// # #![feature(rustc_private)]
-/// # #[allow(unused_extern_crates)]
-/// # extern crate rustc_middle;
-/// # #[allow(unused_extern_crates)]
-/// # extern crate rustc_session;
-/// # #[macro_use]
-/// # use clippy_lints::declare_clippy_lint;
+/// #![feature(rustc_private)]
+/// extern crate rustc_session;
 /// use rustc_session::declare_tool_lint;
+/// use clippy_lints::declare_clippy_lint;
 ///
 /// declare_clippy_lint! {
 ///     /// **What it does:** Checks for ... (describe what the lint matches).
@@ -1062,7 +1039,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
     let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
     store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
-    store.register_early_pass(|| box macro_use::MacroUseImports);
     store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
     store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
     store.register_late_pass(|| box unnamed_address::UnnamedAddress);
@@ -1080,6 +1056,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         single_char_binding_names_threshold,
     });
     store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
+    store.register_late_pass(|| box macro_use::MacroUseImports::default());
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1187,6 +1164,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::OPTION_OPTION),
         LintId::of(&unicode::NON_ASCII_LITERAL),
         LintId::of(&unicode::UNICODE_NOT_NFC),
+        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unused_self::UNUSED_SELF),
         LintId::of(&wildcard_imports::ENUM_GLOB_USE),
         LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
@@ -1440,7 +1418,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
         LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
-        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
         LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
         LintId::of(&unwrap::PANICKING_UNWRAP),
@@ -1624,7 +1601,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::UNNECESSARY_CAST),
         LintId::of(&types::VEC_BOX),
         LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
-        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
         LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
index 83093ec51bd9037dd52569934fcb72bc1576b8f3..9c8e8d8fabf4e99aabbc5da3180e26f528bfdfb4 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use std::iter::{once, Iterator};
 use std::mem;
 
@@ -1497,7 +1497,7 @@ struct MutatePairDelegate<'a, 'tcx> {
     span_high: Option<Span>,
 }
 
-impl<'a, 'tcx> Delegate<'tcx> for MutatePairDelegate<'a, 'tcx> {
+impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {}
 
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
@@ -1525,7 +1525,7 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
     }
 }
 
-impl<'a, 'tcx> MutatePairDelegate<'a, 'tcx> {
+impl MutatePairDelegate<'_, '_> {
     fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
         (self.span_low, self.span_high)
     }
@@ -1580,13 +1580,13 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr<'_>) -> Option<Hi
     None
 }
 
-fn check_for_mutation<'a, 'tcx> (
+fn check_for_mutation<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     body: &Expr<'_>,
     bound_ids: &[Option<HirId>],
 ) -> (Option<Span>, Option<Span>) {
     let mut delegate = MutatePairDelegate {
-        cx: cx,
+        cx,
         hir_id_low: bound_ids[0],
         hir_id_high: bound_ids[1],
         span_low: None,
@@ -2042,7 +2042,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if self.state == VarState::DontWarn {
             return;
         }
-        if SpanlessEq::new(self.cx).eq_expr(&expr, self.end_expr) {
+        if expr.hir_id == self.end_expr.hir_id {
             self.past_loop = true;
             return;
         }
@@ -2292,7 +2292,7 @@ struct HasBreakOrReturnVisitor {
     has_break_or_return: bool,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
+impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
index b1345d0b751ae3b22acf860b2a591fcf547e1f9a..b845b20d2c012c6dc6b4193d36a1b79da03ee2b2 100644 (file)
@@ -1,10 +1,13 @@
-use crate::utils::{snippet, span_lint_and_sugg};
+use crate::utils::{in_macro, snippet, span_lint_and_sugg};
+use hir::def::{DefKind, Res};
 use if_chain::if_chain;
 use rustc_ast::ast;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::edition::Edition;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{edition::Edition, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `#[macro_use] use...`.
@@ -12,7 +15,7 @@
     /// **Why is this bad?** Since the Rust 2018 edition you can import
     /// macro's directly, this is considered idiomatic.
     ///
-    /// **Known problems:** This lint does not generate an auto-applicable suggestion.
+    /// **Known problems:** None.
     ///
     /// **Example:**
     /// ```rust
     "#[macro_use] is no longer needed"
 }
 
-declare_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
+const BRACKETS: &[char] = &['<', '>'];
 
-impl EarlyLintPass for MacroUseImports {
-    fn check_item(&mut self, ecx: &EarlyContext<'_>, item: &ast::Item) {
+#[derive(Clone, Debug, PartialEq, Eq)]
+struct PathAndSpan {
+    path: String,
+    span: Span,
+}
+
+/// `MacroRefData` includes the name of the macro
+/// and the path from `SourceMap::span_to_filename`.
+#[derive(Debug, Clone)]
+pub struct MacroRefData {
+    name: String,
+    path: String,
+}
+
+impl MacroRefData {
+    pub fn new(name: String, callee: Span, cx: &LateContext<'_, '_>) -> Self {
+        let mut path = cx.sess().source_map().span_to_filename(callee).to_string();
+
+        // std lib paths are <::std::module::file type>
+        // so remove brackets, space and type.
+        if path.contains('<') {
+            path = path.replace(BRACKETS, "");
+        }
+        if path.contains(' ') {
+            path = path.split(' ').next().unwrap().to_string();
+        }
+        Self { name, path }
+    }
+}
+
+#[derive(Default)]
+#[allow(clippy::module_name_repetitions)]
+pub struct MacroUseImports {
+    /// the actual import path used and the span of the attribute above it.
+    imports: Vec<(String, Span)>,
+    /// the span of the macro reference, kept to ensure only one reference is used per macro call.
+    collected: FxHashSet<Span>,
+    mac_refs: Vec<MacroRefData>,
+}
+
+impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
+
+impl MacroUseImports {
+    fn push_unique_macro(&mut self, cx: &LateContext<'_, '_>, span: Span) {
+        let call_site = span.source_callsite();
+        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
+        if let Some(callee) = span.source_callee() {
+            if !self.collected.contains(&call_site) {
+                let name = if name.contains("::") {
+                    name.split("::").last().unwrap().to_string()
+                } else {
+                    name.to_string()
+                };
+
+                self.mac_refs.push(MacroRefData::new(name, callee.def_site, cx));
+                self.collected.insert(call_site);
+            }
+        }
+    }
+
+    fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_, '_>, span: Span) {
+        let call_site = span.source_callsite();
+        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
+        if let Some(callee) = span.source_callee() {
+            if !self.collected.contains(&call_site) {
+                self.mac_refs
+                    .push(MacroRefData::new(name.to_string(), callee.def_site, cx));
+                self.collected.insert(call_site);
+            }
+        }
+    }
+}
+
+impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
+    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
         if_chain! {
-            if ecx.sess.opts.edition == Edition::Edition2018;
-            if let ast::ItemKind::Use(use_tree) = &item.kind;
+            if cx.sess().opts.edition == Edition::Edition2018;
+            if let hir::ItemKind::Use(path, _kind) = &item.kind;
             if let Some(mac_attr) = item
                 .attrs
                 .iter()
                 .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
+            if let Res::Def(DefKind::Mod, id) = path.res;
             then {
-                let msg = "`macro_use` attributes are no longer needed in the Rust 2018 edition";
-                let help = format!("use {}::<macro name>", snippet(ecx, use_tree.span, "_"));
+                for kid in cx.tcx.item_children(id).iter() {
+                    if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
+                        let span = mac_attr.span;
+                        let def_path = cx.tcx.def_path_str(mac_id);
+                        self.imports.push((def_path, span));
+                    }
+                }
+            } else {
+                if in_macro(item.span) {
+                    self.push_unique_macro_pat_ty(cx, item.span);
+                }
+            }
+        }
+    }
+    fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) {
+        if in_macro(attr.span) {
+            self.push_unique_macro(cx, attr.span);
+        }
+    }
+    fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
+        if in_macro(expr.span) {
+            self.push_unique_macro(cx, expr.span);
+        }
+    }
+    fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>) {
+        if in_macro(stmt.span) {
+            self.push_unique_macro(cx, stmt.span);
+        }
+    }
+    fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
+        if in_macro(pat.span) {
+            self.push_unique_macro_pat_ty(cx, pat.span);
+        }
+    }
+    fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &hir::Ty<'_>) {
+        if in_macro(ty.span) {
+            self.push_unique_macro_pat_ty(cx, ty.span);
+        }
+    }
+    #[allow(clippy::too_many_lines)]
+    fn check_crate_post(&mut self, cx: &LateContext<'_, '_>, _krate: &hir::Crate<'_>) {
+        let mut used = FxHashMap::default();
+        let mut check_dup = vec![];
+        for (import, span) in &self.imports {
+            let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name));
+
+            if let Some(idx) = found_idx {
+                let _ = self.mac_refs.remove(idx);
+                let seg = import.split("::").collect::<Vec<_>>();
+
+                match seg.as_slice() {
+                    // an empty path is impossible
+                    // a path should always consist of 2 or more segments
+                    [] | [_] => return,
+                    [root, item] => {
+                        if !check_dup.contains(&(*item).to_string()) {
+                            used.entry(((*root).to_string(), span))
+                                .or_insert_with(Vec::new)
+                                .push((*item).to_string());
+                            check_dup.push((*item).to_string());
+                        }
+                    },
+                    [root, rest @ ..] => {
+                        if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) {
+                            let filtered = rest
+                                .iter()
+                                .filter_map(|item| {
+                                    if check_dup.contains(&(*item).to_string()) {
+                                        None
+                                    } else {
+                                        Some((*item).to_string())
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            used.entry(((*root).to_string(), span))
+                                .or_insert_with(Vec::new)
+                                .push(filtered.join("::"));
+                            check_dup.extend(filtered);
+                        } else {
+                            let rest = rest.to_vec();
+                            used.entry(((*root).to_string(), span))
+                                .or_insert_with(Vec::new)
+                                .push(rest.join("::"));
+                            check_dup.extend(rest.iter().map(ToString::to_string));
+                        }
+                    },
+                }
+            }
+        }
+
+        let mut suggestions = vec![];
+        for ((root, span), path) in used {
+            if path.len() == 1 {
+                suggestions.push((span, format!("{}::{}", root, path[0])))
+            } else {
+                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+            }
+        }
+
+        // If mac_refs is not empty we have encountered an import we could not handle
+        // such as `std::prelude::v1::foo` or some other macro that expands to an import.
+        if self.mac_refs.is_empty() {
+            for (span, import) in suggestions {
+                let help = format!("use {};", import);
                 span_lint_and_sugg(
-                    ecx,
+                    cx,
                     MACRO_USE_IMPORTS,
-                    mac_attr.span,
-                    msg,
+                    *span,
+                    "`macro_use` attributes are no longer needed in the Rust 2018 edition",
                     "remove the attribute and import the macro directly, try",
                     help,
-                    Applicability::HasPlaceholders,
-                );
+                    Applicability::MaybeIncorrect,
+                )
             }
         }
     }
index ab6865bf0f3b7675edd08a150d2c0dd0c4eee121..e2672e02b36da586d004b85d4d5241050369eecb 100644 (file)
@@ -135,33 +135,59 @@ fn check_replace_option_with_none(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest
     }
 }
 
-fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span: Span) {
-    if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind {
-        if_chain! {
-            if repl_args.is_empty();
-            if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
-            if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
-            then {
-                if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
-                    span_lint_and_help(
-                        cx,
-                        MEM_REPLACE_WITH_UNINIT,
-                        expr_span,
-                        "replacing with `mem::uninitialized()`",
-                        None,
-                        "consider using the `take_mut` crate instead",
-                    );
-                } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
-                        !cx.tables.expr_ty(src).is_primitive() {
-                    span_lint_and_help(
-                        cx,
-                        MEM_REPLACE_WITH_UNINIT,
-                        expr_span,
-                        "replacing with `mem::zeroed()`",
-                        None,
-                        "consider using a default value or the `take_mut` crate instead",
-                    );
-                }
+fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
+    if_chain! {
+        // check if replacement is mem::MaybeUninit::uninit().assume_init()
+        if let Some(method_def_id) = cx.tables.type_dependent_def_id(src.hir_id);
+        if cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id);
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                MEM_REPLACE_WITH_UNINIT,
+                expr_span,
+                "replacing with `mem::MaybeUninit::uninit().assume_init()`",
+                "consider using",
+                format!(
+                    "std::ptr::read({})",
+                    snippet_with_applicability(cx, dest.span, "", &mut applicability)
+                ),
+                applicability,
+            );
+            return;
+        }
+    }
+
+    if_chain! {
+        if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind;
+        if repl_args.is_empty();
+        if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
+        if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
+        then {
+            if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
+                let mut applicability = Applicability::MachineApplicable;
+                span_lint_and_sugg(
+                    cx,
+                    MEM_REPLACE_WITH_UNINIT,
+                    expr_span,
+                    "replacing with `mem::uninitialized()`",
+                    "consider using",
+                    format!(
+                        "std::ptr::read({})",
+                        snippet_with_applicability(cx, dest.span, "", &mut applicability)
+                    ),
+                    applicability,
+                );
+            } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
+                    !cx.tables.expr_ty(src).is_primitive() {
+                span_lint_and_help(
+                    cx,
+                    MEM_REPLACE_WITH_UNINIT,
+                    expr_span,
+                    "replacing with `mem::zeroed()`",
+                    None,
+                    "consider using a default value or the `take_mut` crate instead",
+                );
             }
         }
     }
@@ -209,7 +235,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let [dest, src] = &**func_args;
             then {
                 check_replace_option_with_none(cx, src, dest, expr.span);
-                check_replace_with_uninit(cx, src, expr.span);
+                check_replace_with_uninit(cx, src, dest, expr.span);
                 check_replace_with_default(cx, src, dest, expr.span);
             }
         }
index dd236535c18ad9d6aed4c0fc5105d1b12f598a78..42200385932b0ee5612e2b9d9c5a28add04d4dbb 100644 (file)
@@ -33,7 +33,7 @@
     /// }
     /// ```
     ///
-    /// To fix the lint, and a `Default` implementation that delegates to `new`:
+    /// To fix the lint, add a `Default` implementation that delegates to `new`:
     ///
     /// ```ignore
     /// struct Foo(Bar);
index f16b916441ae81a51142998a4590b099845cba29..3c528a295b044ba34b2176638d2761de37ad3aad 100644 (file)
@@ -1,10 +1,13 @@
-use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
+use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_mir::const_eval::is_const_fn;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Symbol;
 
 declare_clippy_lint! {
     /// **What it does:** Lint for redundant pattern matching over `Result` or
@@ -64,26 +67,37 @@ fn find_sugg_for_if_let<'a, 'tcx>(
     arms: &[Arm<'_>],
     keyword: &'static str,
 ) {
+    fn find_suggestion(cx: &LateContext<'_, '_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
+        if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
+            return Some("is_ok()");
+        }
+        if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
+            return Some("is_err()");
+        }
+        if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
+            return Some("is_some()");
+        }
+        if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
+            return Some("is_none()");
+        }
+        None
+    }
+
+    let hir_id = expr.hir_id;
     let good_method = match arms[0].pat.kind {
         PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
             if let PatKind::Wild = patterns[0].kind {
-                if match_qpath(path, &paths::RESULT_OK) {
-                    "is_ok()"
-                } else if match_qpath(path, &paths::RESULT_ERR) {
-                    "is_err()"
-                } else if match_qpath(path, &paths::OPTION_SOME) {
-                    "is_some()"
-                } else {
-                    return;
-                }
+                find_suggestion(cx, hir_id, path)
             } else {
-                return;
+                None
             }
         },
-
-        PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
-
-        _ => return,
+        PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
+        _ => None,
+    };
+    let good_method = match good_method {
+        Some(method) => method,
+        None => return,
     };
 
     // check that `while_let_on_iterator` lint does not trigger
@@ -128,6 +142,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
+        let hir_id = expr.hir_id;
         let found_good_method = match node_pair {
             (
                 PatKind::TupleStruct(ref path_left, ref patterns_left, _),
@@ -142,6 +157,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
                         &paths::RESULT_ERR,
                         "is_ok()",
                         "is_err()",
+                        || can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
+                        || can_suggest(cx, hir_id, sym!(result_type), "is_err"),
                     )
                 } else {
                     None
@@ -160,6 +177,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
                         &paths::OPTION_NONE,
                         "is_some()",
                         "is_none()",
+                        || can_suggest(cx, hir_id, sym!(option_type), "is_some"),
+                        || can_suggest(cx, hir_id, sym!(option_type), "is_none"),
                     )
                 } else {
                     None
@@ -188,6 +207,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
     }
 }
 
+#[allow(clippy::too_many_arguments)]
 fn find_good_method_for_match<'a>(
     arms: &[Arm<'_>],
     path_left: &QPath<'_>,
@@ -196,6 +216,8 @@ fn find_good_method_for_match<'a>(
     expected_right: &[&str],
     should_be_left: &'a str,
     should_be_right: &'a str,
+    can_suggest_left: impl Fn() -> bool,
+    can_suggest_right: impl Fn() -> bool,
 ) -> Option<&'a str> {
     let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
         (&(*arms[0].body).kind, &(*arms[1].body).kind)
@@ -207,10 +229,32 @@ fn find_good_method_for_match<'a>(
 
     match body_node_pair {
         (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
+            (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
             _ => None,
         },
         _ => None,
     }
 }
+
+fn can_suggest(cx: &LateContext<'_, '_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
+    if !in_constant(cx, hir_id) {
+        return true;
+    }
+
+    // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
+    cx.tcx
+        .get_diagnostic_item(diag_item)
+        .and_then(|def_id| {
+            cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
+                cx.tcx
+                    .associated_items(*imp)
+                    .in_definition_order()
+                    .find_map(|item| match item.kind {
+                        ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
+                        _ => None,
+                    })
+            })
+        })
+        .map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
+}
index a9e6fa329c0f03ab2681222320afcce1f6fcfbb9..cf71c3144a2ebebac537498f2748d45ca23d1211 100644 (file)
@@ -184,7 +184,7 @@ struct BinaryExprVisitor {
     in_binary_expr: bool,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for BinaryExprVisitor {
+impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
index 8e0cb94317affc2ce1bf3c0e81d3407fda751bf9..146ac4b09d5a4ff503bbf43ea09b52f3e4e5366a 100644 (file)
@@ -58,7 +58,7 @@ pub struct TriviallyCopyPassByRef {
     limit: u64,
 }
 
-impl<'a, 'tcx> TriviallyCopyPassByRef {
+impl<'tcx> TriviallyCopyPassByRef {
     pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
         let limit = limit.unwrap_or_else(|| {
             let bit_width = u64::from(target.ptr_width);
index d59a2f1bae031f14a72269ed06902c45d53c327b..98de08f79f3d7872a61a3b18c878a7f8b222c40b 100644 (file)
@@ -1945,16 +1945,12 @@ fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
 
     let which = match (&ty.kind, cv) {
         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
-        (&ty::Int(ity), Constant::Int(i))
-            if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) =>
-        {
+        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
             Minimum
         },
 
         (&ty::Bool, Constant::Bool(true)) => Maximum,
-        (&ty::Int(ity), Constant::Int(i))
-            if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) =>
-        {
+        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
             Maximum
         },
         (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum,
@@ -2083,50 +2079,20 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'_>)
         }
         match pre_cast_ty.kind {
             ty::Int(int_ty) => Some(match int_ty {
-                IntTy::I8 => (
-                    FullInt::S(i128::from(i8::MIN)),
-                    FullInt::S(i128::from(i8::MAX)),
-                ),
-                IntTy::I16 => (
-                    FullInt::S(i128::from(i16::MIN)),
-                    FullInt::S(i128::from(i16::MAX)),
-                ),
-                IntTy::I32 => (
-                    FullInt::S(i128::from(i32::MIN)),
-                    FullInt::S(i128::from(i32::MAX)),
-                ),
-                IntTy::I64 => (
-                    FullInt::S(i128::from(i64::MIN)),
-                    FullInt::S(i128::from(i64::MAX)),
-                ),
+                IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
+                IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
+                IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
+                IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
                 IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
-                IntTy::Isize => (
-                    FullInt::S(isize::MIN as i128),
-                    FullInt::S(isize::MAX as i128),
-                ),
+                IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
             }),
             ty::Uint(uint_ty) => Some(match uint_ty {
-                UintTy::U8 => (
-                    FullInt::U(u128::from(u8::MIN)),
-                    FullInt::U(u128::from(u8::MAX)),
-                ),
-                UintTy::U16 => (
-                    FullInt::U(u128::from(u16::MIN)),
-                    FullInt::U(u128::from(u16::MAX)),
-                ),
-                UintTy::U32 => (
-                    FullInt::U(u128::from(u32::MIN)),
-                    FullInt::U(u128::from(u32::MAX)),
-                ),
-                UintTy::U64 => (
-                    FullInt::U(u128::from(u64::MIN)),
-                    FullInt::U(u128::from(u64::MAX)),
-                ),
+                UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
+                UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
+                UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
+                UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
                 UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
-                UintTy::Usize => (
-                    FullInt::U(usize::MIN as u128),
-                    FullInt::U(usize::MAX as u128),
-                ),
+                UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
             }),
             _ => None,
         }
index e94eebb88e4974bd10511c483ed24101051a2db5..6ac6a12529c868c13e0c903bcb8b8c6b68660e83 100644 (file)
@@ -95,7 +95,10 @@ fn mirrored_exprs(
         // The two exprs are method calls.
         // Check to see that the function is the same and the arguments are mirrored
         // This is enough because the receiver of the method is listed in the arguments
-        (ExprKind::MethodCall(left_segment, _, left_args, _), ExprKind::MethodCall(right_segment, _, right_args, _)) => {
+        (
+            ExprKind::MethodCall(left_segment, _, left_args, _),
+            ExprKind::MethodCall(right_segment, _, right_args, _),
+        ) => {
             left_segment.ident == right_segment.ident
                 && left_args
                     .iter()
index 8c281126c32bf8c954b7e1c057e6ced0c8573e49..4d3682263f14fdedc14be9209e1806147937190d 100644 (file)
@@ -45,7 +45,7 @@
     /// }
     /// ```
     pub UNNESTED_OR_PATTERNS,
-    complexity,
+    pedantic,
     "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
 }
 
index 8b58bbb5e65753e46089033998458100b72cb4c3..910b665ccb75ea2fcc1a4682df2e021fd0be9a55 100644 (file)
@@ -251,7 +251,10 @@ fn visit_expr(&mut self, expr: &Expr<'_>) {
                 }
             },
             ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => {
-                println!("MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};", current);
+                println!(
+                    "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
+                    current
+                );
                 println!("    // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
             },
             ExprKind::Tup(ref elements) => {
index 9e8e0ff30ec6b761a2d29566716163f6ca4ac014..c41befbf147b8c2e1567b86f50262ec0c9359009 100644 (file)
@@ -106,8 +106,8 @@ fn $config() -> $Ty {
 
 pub use self::helpers::Conf;
 define_Conf! {
-    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
-    (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "bar", "baz", "quux"].iter().map(ToString::to_string).collect()),
+    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
+    (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
     /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
     (cognitive_complexity_threshold, "cognitive_complexity_threshold": u64, 25),
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
index 7a84f1c986aa7dc4d059d7cf9314eb0ac187e460..9a9aa3f94eb4b64ad6bfe491d82aee84442ddd02 100644 (file)
@@ -309,18 +309,15 @@ fn swap_binop<'a>(
     rhs: &'a Expr<'a>,
 ) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> {
     match binop {
-        BinOpKind::Add
-        | BinOpKind::Mul
-        | BinOpKind::Eq
-        | BinOpKind::Ne
-        | BinOpKind::BitAnd
-        | BinOpKind::BitXor
-        | BinOpKind::BitOr => Some((binop, rhs, lhs)),
+        BinOpKind::Add | BinOpKind::Eq | BinOpKind::Ne | BinOpKind::BitAnd | BinOpKind::BitXor | BinOpKind::BitOr => {
+            Some((binop, rhs, lhs))
+        },
         BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)),
         BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)),
         BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)),
         BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)),
-        BinOpKind::Shl
+        BinOpKind::Mul // Not always commutative, e.g. with matrices. See issue #5698
+        | BinOpKind::Shl
         | BinOpKind::Shr
         | BinOpKind::Rem
         | BinOpKind::Sub
index 73758b7eeb7eb28e27651a9ec36b9cc333e622d4..e919b1522d89a04f12c0140b2e45dfc9a8901a6c 100644 (file)
@@ -509,7 +509,7 @@ fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 }
 
 /// Convenience extension trait for `DiagnosticBuilder`.
-pub trait DiagnosticBuilderExt<'a, T: LintContext> {
+pub trait DiagnosticBuilderExt<T: LintContext> {
     /// Suggests to add an attribute to an item.
     ///
     /// Correctly handles indentation of the attribute and item.
@@ -556,7 +556,7 @@ fn suggest_item_with_attr<D: Display + ?Sized>(
     fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability);
 }
 
-impl<'a, 'b, 'c, T: LintContext> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
+impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder<'_> {
     fn suggest_item_with_attr<D: Display + ?Sized>(
         &mut self,
         cx: &T,
index 6a7a1f1ceaaef8fabe9cfa38e331e237b303db8c..0492878fc272f19a8028fa6ac04a168fd76c6a8b 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_span::symbol::{Ident, Symbol};
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
 pub fn mutated_variables<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<HirId>> {
index b637253bd0264666418adde8d5c4c86f6f55beee..79f7705e281e542806d081fdae55c5e6549220e0 100644 (file)
@@ -36,7 +36,7 @@
 declare_clippy_lint! {
     /// **What it does:** Checks for wildcard imports `use _::*`.
     ///
-    /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
+    /// **Why is this bad?** wildcard imports can pollute the namespace. This is especially bad if
     /// you try to import something through a wildcard, that already has been imported by name from
     /// a different source:
     ///
index 4453ae5ce4414b221eb7784c41dc9114cdd3095f..decd3a79cce180c839320dc158f5714c095150c2 100644 (file)
@@ -1,15 +1,16 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![feature(rustc_private)]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![deny(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
-#[allow(unused_extern_crates)]
+extern crate rustc_data_structures;
 extern crate rustc_driver;
-#[allow(unused_extern_crates)]
 extern crate rustc_errors;
-#[allow(unused_extern_crates)]
 extern crate rustc_interface;
-#[allow(unused_extern_crates)]
 extern crate rustc_middle;
 
 use rustc_interface::interface;
@@ -93,7 +94,7 @@ fn config(&mut self, config: &mut interface::Config) {
 #[allow(clippy::find_map, clippy::filter_map)]
 fn describe_lints() {
     use lintlist::{Level, Lint, ALL_LINTS, LINT_LEVELS};
-    use std::collections::HashSet;
+    use rustc_data_structures::fx::FxHashSet;
 
     println!(
         "
@@ -137,7 +138,7 @@ fn describe_lints() {
 
     let scoped = |x: &str| format!("clippy::{}", x);
 
-    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();
+    let lint_groups: FxHashSet<_> = lints.iter().map(|lint| lint.group).collect();
 
     println!("Lint checks provided by clippy:\n");
     println!("    {}  {:7.7}  meaning", padded("name"), "default");
@@ -207,6 +208,7 @@ fn display_help() {
 
 Common options:
     -h, --help               Print this message
+        --rustc              Pass all args to rustc
     -V, --version            Print version info and exit
 
 Other options are the same as `cargo check`.
@@ -297,12 +299,6 @@ pub fn main() {
     exit(rustc_driver::catch_with_exit_code(move || {
         let mut orig_args: Vec<String> = env::args().collect();
 
-        if orig_args.iter().any(|a| a == "--version" || a == "-V") {
-            let version_info = rustc_tools_util::get_version_info!();
-            println!("{}", version_info);
-            exit(0);
-        }
-
         // Get the sysroot, looking from most specific to this invocation to the least:
         // - command line
         // - runtime environment
@@ -348,6 +344,28 @@ pub fn main() {
             .map(|pb| pb.to_string_lossy().to_string())
             .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
 
+        // make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc"
+        // for example `clippy-driver --rustc --version` will print the rustc version that clippy-driver
+        // uses
+        if let Some(pos) = orig_args.iter().position(|arg| arg == "--rustc") {
+            orig_args.remove(pos);
+            orig_args[0] = "rustc".to_string();
+
+            // if we call "rustc", we need to pass --sysroot here as well
+            let mut args: Vec<String> = orig_args.clone();
+            if !have_sys_root_arg {
+                args.extend(vec!["--sysroot".into(), sys_root]);
+            };
+
+            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None);
+        }
+
+        if orig_args.iter().any(|a| a == "--version" || a == "-V") {
+            let version_info = rustc_tools_util::get_version_info!();
+            println!("{}", version_info);
+            exit(0);
+        }
+
         // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
         // We're invoking the compiler programmatically, so we ignore this/
         let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());
index cac3cc6bdb316eb2891ff3b4d99d1001371ebfbd..edceb75518008e798915dc815e52561662431a31 100644 (file)
     },
     Lint {
         name: "unnested_or_patterns",
-        group: "complexity",
+        group: "pedantic",
         desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`",
         deprecation: None,
         module: "unnested_or_patterns",
index bc43a34ed5d4aaa4e843306abfebab9970a955f2..6739a4cf2245e5e16a7aed73e135edf3d9ab9424 100644 (file)
@@ -1,4 +1,6 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
 
 use rustc_tools_util::VersionInfo;
 use std::env;
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs b/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs
new file mode 100644 (file)
index 0000000..ecb55d8
--- /dev/null
@@ -0,0 +1,60 @@
+extern crate macro_rules;
+
+// STMT
+#[macro_export]
+macro_rules! pub_macro {
+    () => {
+        let _ = "hello Mr. Vonnegut";
+    };
+}
+
+pub mod inner {
+    pub use super::*;
+
+    // RE-EXPORT
+    // this will stick in `inner` module
+    pub use macro_rules::foofoo;
+    pub use macro_rules::try_err;
+
+    pub mod nested {
+        pub use macro_rules::string_add;
+    }
+
+    // ITEM
+    #[macro_export]
+    macro_rules! inner_mod_macro {
+        () => {
+            #[allow(dead_code)]
+            pub struct Tardis;
+        };
+    }
+}
+
+// EXPR
+#[macro_export]
+macro_rules! function_macro {
+    () => {
+        if true {
+        } else {
+        }
+    };
+}
+
+// TYPE
+#[macro_export]
+macro_rules! ty_macro {
+    () => {
+        Vec<u8>
+    };
+}
+
+mod extern_exports {
+    pub(super) mod private_inner {
+        #[macro_export]
+        macro_rules! pub_in_private_macro {
+            ($name:ident) => {
+                let $name = String::from("secrets and lies");
+            };
+        }
+    }
+}
index ca9d8d16b787df5af6c08f834306dd49d9ed3cf2..cb15bdd2f1b2d4cca8383b2967a535ee3d3ae20f 100644 (file)
@@ -12,29 +12,34 @@ fn test(foo: ()) {}
 
 fn main() {
     let foo = 42;
-    let bar = 42;
     let baz = 42;
+    let quux = 42;
+    // Unlike these others, `bar` is actually considered an acceptable name.
+    // Among many other legitimate uses, bar commonly refers to a period of time in music.
+    // See https://github.com/rust-lang/rust-clippy/issues/5225.
+    let bar = 42;
 
-    let barb = 42;
-    let barbaric = 42;
+    let food = 42;
+    let foodstuffs = 42;
+    let bazaar = 42;
 
     match (42, Some(1337), Some(0)) {
-        (foo, Some(bar), baz @ Some(_)) => (),
+        (foo, Some(baz), quux @ Some(_)) => (),
         _ => (),
     }
 }
 
 fn issue_1647(mut foo: u8) {
-    let mut bar = 0;
-    if let Some(mut baz) = Some(42) {}
+    let mut baz = 0;
+    if let Some(mut quux) = Some(42) {}
 }
 
 fn issue_1647_ref() {
-    let ref bar = 0;
-    if let Some(ref baz) = Some(42) {}
+    let ref baz = 0;
+    if let Some(ref quux) = Some(42) {}
 }
 
 fn issue_1647_ref_mut() {
-    let ref mut bar = 0;
-    if let Some(ref mut baz) = Some(42) {}
+    let ref mut baz = 0;
+    if let Some(ref mut quux) = Some(42) {}
 }
index 44123829fb0f651208a28aa35f981a94f42c99a5..70dbdaece8b6bb37083a79cb0d0bafc9b6c00a86 100644 (file)
@@ -12,77 +12,77 @@ error: use of a blacklisted/placeholder name `foo`
 LL |     let foo = 42;
    |         ^^^
 
-error: use of a blacklisted/placeholder name `bar`
+error: use of a blacklisted/placeholder name `baz`
   --> $DIR/blacklisted_name.rs:15:9
    |
-LL |     let bar = 42;
+LL |     let baz = 42;
    |         ^^^
 
-error: use of a blacklisted/placeholder name `baz`
+error: use of a blacklisted/placeholder name `quux`
   --> $DIR/blacklisted_name.rs:16:9
    |
-LL |     let baz = 42;
-   |         ^^^
+LL |     let quux = 42;
+   |         ^^^^
 
 error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:22:10
+  --> $DIR/blacklisted_name.rs:27:10
    |
-LL |         (foo, Some(bar), baz @ Some(_)) => (),
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
    |          ^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:22:20
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:27:20
    |
-LL |         (foo, Some(bar), baz @ Some(_)) => (),
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
    |                    ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:22:26
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:27:26
    |
-LL |         (foo, Some(bar), baz @ Some(_)) => (),
-   |                          ^^^
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |                          ^^^^
 
 error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:27:19
+  --> $DIR/blacklisted_name.rs:32:19
    |
 LL | fn issue_1647(mut foo: u8) {
    |                   ^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:28:13
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:33:13
    |
-LL |     let mut bar = 0;
+LL |     let mut baz = 0;
    |             ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:29:21
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:34:21
    |
-LL |     if let Some(mut baz) = Some(42) {}
-   |                     ^^^
+LL |     if let Some(mut quux) = Some(42) {}
+   |                     ^^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:33:13
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:38:13
    |
-LL |     let ref bar = 0;
+LL |     let ref baz = 0;
    |             ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:34:21
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:39:21
    |
-LL |     if let Some(ref baz) = Some(42) {}
-   |                     ^^^
+LL |     if let Some(ref quux) = Some(42) {}
+   |                     ^^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:38:17
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:43:17
    |
-LL |     let ref mut bar = 0;
+LL |     let ref mut baz = 0;
    |                 ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:39:25
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:44:25
    |
-LL |     if let Some(ref mut baz) = Some(42) {}
-   |                         ^^^
+LL |     if let Some(ref mut quux) = Some(42) {}
+   |                         ^^^^
 
 error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5389.rs b/src/tools/clippy/tests/ui/crashes/ice-5389.rs
new file mode 100644 (file)
index 0000000..de26219
--- /dev/null
@@ -0,0 +1,13 @@
+#![allow(clippy::explicit_counter_loop)]
+
+fn main() {
+    let v = vec![1, 2, 3];
+    let mut i = 0;
+    let max_storage_size = [0; 128 * 1024];
+    for item in &v {
+        bar(i, *item);
+        i += 1;
+    }
+}
+
+fn bar(_: usize, _: u32) {}
index 6bbf79edfcf700c75eb9444bb79ea12ef141af17..9c5fe02f7519bd25b178af70bf7b01da77520463 100644 (file)
@@ -142,4 +142,16 @@ fn func() {
 
 fn f(val: &[u8]) {}
 
+mod issue_5698 {
+    fn mul_not_always_commutative(x: i32, y: i32) -> i32 {
+        if x == 42 {
+            x * y
+        } else if x == 21 {
+            y * x
+        } else {
+            0
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed
new file mode 100644 (file)
index 0000000..91e34c6
--- /dev/null
@@ -0,0 +1,43 @@
+// compile-flags: --edition 2018
+// aux-build:macro_rules.rs
+// aux-build:macro_use_helper.rs
+// run-rustfix
+// ignore-32bit
+
+#![allow(unused_imports, unreachable_code, unused_variables, dead_code)]
+#![allow(clippy::single_component_path_imports)]
+#![warn(clippy::macro_use_imports)]
+
+#[macro_use]
+extern crate macro_use_helper as mac;
+
+#[macro_use]
+extern crate clippy_mini_macro_test as mini_mac;
+
+mod a {
+    use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
+    use mac;
+    use mini_mac::ClippyMiniMacroTest;
+    use mini_mac;
+    use mac::{inner::foofoo, inner::try_err};
+    use mac::inner;
+    use mac::inner::nested::string_add;
+    use mac::inner::nested;
+
+    #[derive(ClippyMiniMacroTest)]
+    struct Test;
+
+    fn test() {
+        pub_macro!();
+        inner_mod_macro!();
+        pub_in_private_macro!(_var);
+        function_macro!();
+        let v: ty_macro!() = Vec::default();
+
+        inner::try_err!();
+        inner::foofoo!();
+        nested::string_add!();
+    }
+}
+
+fn main() {}
index 60c64ee8146e517f71f28f1c0f62c9600bea9fd0..9c3c50c5d49f29b0a03eea1ca77c583a71686597 100644 (file)
@@ -1,11 +1,43 @@
-// edition:2018
+// compile-flags: --edition 2018
+// aux-build:macro_rules.rs
+// aux-build:macro_use_helper.rs
+// run-rustfix
+// ignore-32bit
+
+#![allow(unused_imports, unreachable_code, unused_variables, dead_code)]
+#![allow(clippy::single_component_path_imports)]
 #![warn(clippy::macro_use_imports)]
 
-use std::collections::HashMap;
 #[macro_use]
-use std::prelude;
+extern crate macro_use_helper as mac;
+
+#[macro_use]
+extern crate clippy_mini_macro_test as mini_mac;
+
+mod a {
+    #[macro_use]
+    use mac;
+    #[macro_use]
+    use mini_mac;
+    #[macro_use]
+    use mac::inner;
+    #[macro_use]
+    use mac::inner::nested;
 
-fn main() {
-    let _ = HashMap::<u8, u8>::new();
-    println!();
+    #[derive(ClippyMiniMacroTest)]
+    struct Test;
+
+    fn test() {
+        pub_macro!();
+        inner_mod_macro!();
+        pub_in_private_macro!(_var);
+        function_macro!();
+        let v: ty_macro!() = Vec::default();
+
+        inner::try_err!();
+        inner::foofoo!();
+        nested::string_add!();
+    }
 }
+
+fn main() {}
index b5e3dbec572772f2e9aaf7924e0f011eaaedd878..f8c86c8d9179f8af918b684eb9294c18ea4a7008 100644 (file)
@@ -1,10 +1,28 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:5:1
+  --> $DIR/macro_use_imports.rs:18:5
    |
-LL | #[macro_use]
-   | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::<macro name>`
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
    |
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
-error: aborting due to previous error
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+  --> $DIR/macro_use_imports.rs:20:5
+   |
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+  --> $DIR/macro_use_imports.rs:22:5
+   |
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+  --> $DIR/macro_use_imports.rs:24:5
+   |
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+
+error: aborting due to 4 previous errors
 
index fc8cb0e747c73e157e3c17306a2491352c208bf3..6ba5cfb1d7177bef814da42575f40ea9b6301a8a 100644 (file)
@@ -1,5 +1,7 @@
 // run-rustfix
 
+#![feature(const_if_match)]
+#![feature(const_loop)]
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
@@ -67,6 +69,7 @@ fn main() {
     takes_bool(x);
 
     issue5504();
+    issue5697();
 
     let _ = if gen_opt().is_some() {
         1
@@ -117,3 +120,42 @@ fn issue5504() {
     if m!().is_some() {}
     while m!().is_some() {}
 }
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
index 51912dade035677a5372aa97b871eb3aa2f1b62e..17de66f9ad0ebaef6c44f8124879c2550e690e47 100644 (file)
@@ -1,5 +1,7 @@
 // run-rustfix
 
+#![feature(const_if_match)]
+#![feature(const_loop)]
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
@@ -88,6 +90,7 @@ fn main() {
     takes_bool(x);
 
     issue5504();
+    issue5697();
 
     let _ = if let Some(_) = gen_opt() {
         1
@@ -138,3 +141,42 @@ fn try_result_opt() -> Result<i32, i32> {
     if let Some(_) = m!() {}
     while let Some(_) = m!() {}
 }
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
index b58deb7954efe06b90c8516d1b4d52c614b901db..1b9a4b40a2f0210da797e4a7d39a7485bfe20205 100644 (file)
@@ -1,5 +1,5 @@
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:8:12
+  --> $DIR/redundant_pattern_matching.rs:10:12
    |
 LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
@@ -7,67 +7,67 @@ LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:10:12
+  --> $DIR/redundant_pattern_matching.rs:12:12
    |
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:12:12
+  --> $DIR/redundant_pattern_matching.rs:14:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:14:12
+  --> $DIR/redundant_pattern_matching.rs:16:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:16:12
+  --> $DIR/redundant_pattern_matching.rs:18:12
    |
 LL |     if let Some(_) = Some(42) {
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:22:15
+  --> $DIR/redundant_pattern_matching.rs:24:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:24:15
+  --> $DIR/redundant_pattern_matching.rs:26:15
    |
 LL |     while let None = Some(42) {}
    |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:26:15
+  --> $DIR/redundant_pattern_matching.rs:28:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:28:15
+  --> $DIR/redundant_pattern_matching.rs:30:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:30:15
+  --> $DIR/redundant_pattern_matching.rs:32:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:33:15
+  --> $DIR/redundant_pattern_matching.rs:35:15
    |
 LL |     while let Some(_) = v.pop() {
    |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:49:5
+  --> $DIR/redundant_pattern_matching.rs:51:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -76,7 +76,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:54:5
+  --> $DIR/redundant_pattern_matching.rs:56:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -85,7 +85,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:59:5
+  --> $DIR/redundant_pattern_matching.rs:61:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -94,7 +94,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:64:5
+  --> $DIR/redundant_pattern_matching.rs:66:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -103,7 +103,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:69:5
+  --> $DIR/redundant_pattern_matching.rs:71:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -112,7 +112,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:74:5
+  --> $DIR/redundant_pattern_matching.rs:76:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -121,7 +121,7 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:79:13
+  --> $DIR/redundant_pattern_matching.rs:81:13
    |
 LL |       let _ = match None::<()> {
    |  _____________^
@@ -131,61 +131,61 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:84:20
+  --> $DIR/redundant_pattern_matching.rs:86:20
    |
 LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
    |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:87:20
+  --> $DIR/redundant_pattern_matching.rs:89:20
    |
 LL |     let x = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:92:20
+  --> $DIR/redundant_pattern_matching.rs:95:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:94:19
+  --> $DIR/redundant_pattern_matching.rs:97:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:96:19
+  --> $DIR/redundant_pattern_matching.rs:99:19
    |
 LL |     } else if let Ok(_) = gen_res() {
    |            -------^^^^^------------ help: try this: `if gen_res().is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:98:19
+  --> $DIR/redundant_pattern_matching.rs:101:19
    |
 LL |     } else if let Err(_) = gen_res() {
    |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:131:19
+  --> $DIR/redundant_pattern_matching.rs:134:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
    |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:132:16
+  --> $DIR/redundant_pattern_matching.rs:135:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
    |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:138:12
+  --> $DIR/redundant_pattern_matching.rs:141:12
    |
 LL |     if let Some(_) = m!() {}
    |     -------^^^^^^^------- help: try this: `if m!().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:139:15
+  --> $DIR/redundant_pattern_matching.rs:142:15
    |
 LL |     while let Some(_) = m!() {}
    |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed
new file mode 100644 (file)
index 0000000..c8bc545
--- /dev/null
@@ -0,0 +1,46 @@
+// run-rustfix
+
+#![feature(const_if_match)]
+#![feature(const_loop)]
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+    if Ok::<i32, i32>(42).is_ok() {}
+
+    if Err::<i32, i32>(42).is_err() {}
+
+    while Ok::<i32, i32>(10).is_ok() {}
+
+    while Ok::<i32, i32>(10).is_err() {}
+
+    Ok::<i32, i32>(42).is_ok();
+
+    Err::<i32, i32>(42).is_err();
+
+    // These should not be linted until `const_option` is implemented.
+    // See https://github.com/rust-lang/rust/issues/67441
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs
new file mode 100644 (file)
index 0000000..75f37ec
--- /dev/null
@@ -0,0 +1,52 @@
+// run-rustfix
+
+#![feature(const_if_match)]
+#![feature(const_loop)]
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+
+    // These should not be linted until `const_option` is implemented.
+    // See https://github.com/rust-lang/rust/issues/67441
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr
new file mode 100644 (file)
index 0000000..c32292f
--- /dev/null
@@ -0,0 +1,46 @@
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:12:12
+   |
+LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
+   |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:14:12
+   |
+LL |     if let Err(_) = Err::<i32, i32>(42) {}
+   |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:16:15
+   |
+LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:18:15
+   |
+LL |     while let Err(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:20:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:25:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: aborting due to 6 previous errors
+
index 346972b7bb4e0d95e1353040c58c4ed714e8e01b..ad5b8e4857d173f50bcbcd2bc9565e8b6c2d5b6a 100644 (file)
@@ -17,6 +17,12 @@ fn main() {
         std::mem::forget(mem::replace(&mut v, new_v));
     }
 
+    unsafe {
+        let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init());
+        let new_v = might_panic(taken_v);
+        std::mem::forget(mem::replace(&mut v, new_v));
+    }
+
     unsafe {
         let taken_v = mem::replace(&mut v, mem::zeroed());
         let new_v = might_panic(taken_v);
index c1f55d7601e5ccce9592e5653330435d7f114832..09468eeaea4bf9d18dacd1c5c03809c5032909bd 100644 (file)
@@ -2,26 +2,29 @@ error: replacing with `mem::uninitialized()`
   --> $DIR/repl_uninit.rs:15:23
    |
 LL |         let taken_v = mem::replace(&mut v, mem::uninitialized());
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)`
    |
    = note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings`
-   = help: consider using the `take_mut` crate instead
 
-error: replacing with `mem::zeroed()`
+error: replacing with `mem::MaybeUninit::uninit().assume_init()`
   --> $DIR/repl_uninit.rs:21:23
    |
+LL |         let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)`
+
+error: replacing with `mem::zeroed()`
+  --> $DIR/repl_uninit.rs:27:23
+   |
 LL |         let taken_v = mem::replace(&mut v, mem::zeroed());
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a default value or the `take_mut` crate instead
 
 error: replacing with `mem::uninitialized()`
-  --> $DIR/repl_uninit.rs:33:28
+  --> $DIR/repl_uninit.rs:39:28
    |
 LL |     let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using the `take_mut` crate instead
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(uref)`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
index 52d0cbd4bfd7a45dec2cd4f86a8d189267d771e0..6ac7c3b9b474a9dbacfdd4cb11fef57cb95da684 100644 (file)
@@ -4,7 +4,6 @@
 use crate::errors::{Error, ErrorKind};
 use crate::runtest::ProcRes;
 use serde::Deserialize;
-use serde_json;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
index c00b0f02c3a90ab024565cbf2e2a91af3c6f1d4b..134ac66b7d15b475e0bea26932c7959aa3e0d9a9 100644 (file)
@@ -9,8 +9,6 @@
 use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
 use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths};
 use crate::util::logv;
-use env_logger;
-use getopts;
 use getopts::Options;
 use log::*;
 use std::env;
index da1d3db49d70e025940a1fbb66b9cac59a8777e3..30a922057eb20f42e1e9097067c27f17603f7e78 100644 (file)
@@ -25,7 +25,6 @@ pub fn read2(
 
 #[cfg(unix)]
 mod imp {
-    use libc;
     use std::io;
     use std::io::prelude::*;
     use std::mem;
index 95ea4fb078955990b37c64c901dc400a1c18473f..dd0c68ecd4965121ec723ecdf0c0166399be8c92 100644 (file)
@@ -13,7 +13,6 @@
 use crate::json;
 use crate::util::get_pointer_width;
 use crate::util::{logv, PathBufExt};
-use diff;
 use regex::{Captures, Regex};
 use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
 
index 163571bc5b9882906f3ce68924d8707f461f0b77..139e6f73f42169b1f68d009954451e5adf557342 100644 (file)
@@ -269,6 +269,12 @@ function runSearch(query, expected, index, loaded, loadedFile, queryName) {
             break;
         }
         var entry = expected[key];
+
+        if (exact_check == true && entry.length !== results[key].length) {
+            error_text.push(queryName + "==> Expected exactly " + entry.length +
+                            " results but found " + results[key].length + " in '" + key + "'");
+        }
+
         var prev_pos = -1;
         for (var i = 0; i < entry.length; ++i) {
             var entry_pos = lookForEntry(entry[i], results[key]);
@@ -307,8 +313,11 @@ function checkResult(error_text, loadedFile, displaySuccess) {
 }
 
 function runChecks(testFile, loaded, index) {
-    var loadedFile = loadContent(
-        readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
+    var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
+    if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
+        testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+    }
+    var loadedFile = loadContent(testFileContent);
 
     const expected = loadedFile.EXPECTED;
     const query = loadedFile.QUERY;
index 5361a618d4e85371b5e236a090117ec87f94b9f0..73ca7abfed363a96f9ef1017d692546251096af7 100644 (file)
@@ -76,44 +76,106 @@ exclude_labels = [
 ]
 
 [notify-zulip."I-prioritize"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "I-prioritize #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been requested for prioritization."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been requested for prioritization.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize)
+- Priority?
+- Regression?
+- Notify people/groups?
+- Needs `I-nominated`?
+"""
 message_on_remove = "Issue #{number}'s prioritization request has been removed."
 
 [notify-zulip."I-nominated"]
 required_labels = ["T-compiler"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "I-prioritize #{number} {title}"
-message_on_add = "@*WG-prioritization* #{number} has been nominated for discussion in `T-compiler` meeting."
+message_on_add = """\
+@*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated)
+- Already discussed?
+- Worth the meeting time?
+- Add agenda entry:
+  - Why nominated?
+  - Assignee?
+  - Issue? PR? What's the status?
+  - Summary and important details?
+"""
 message_on_remove = "#{number}'s nomination has been removed."
 
 [notify-zulip."beta-nominated"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "Backport #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} has been requested for beta backport."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} has been requested for beta backport.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+Prepare agenda entry:
+- Why nominated?
+- Author, assignee?
+- Important details?
+"""
 message_on_remove = "PR #{number}'s beta backport request has been removed."
 
 [notify-zulip."stable-nominated"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "Backport #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} has been requested for stable backport."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} has been requested for stable backport.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+Prepare agenda entry:
+- Why nominated?
+- Author, assignee?
+- Important details?
+"""
 message_on_remove = "PR #{number}'s stable backport request has been removed."
 
 [notify-zulip."S-waiting-on-team"]
 required_labels = ["T-compiler"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "S-waiting-on-team #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} is waiting on `T-compiler`."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team)
+- Prepare agenda entry:
+  - What is it waiting for?
+  - Important details?
+- Could be resolved quickly? Tag `I-nominated`.
+"""
 message_on_remove = "PR #{number}'s is no longer waiting on `T-compiler`."
 
 [notify-zulip."P-critical"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "P-critical #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-critical`."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+- Notify people/groups?
+- Assign if possible?
+- Add to agenda:
+  - Assignee?
+  - Summary and important details?
+- Other actions to move forward?
+"""
 
 [notify-zulip."P-high"]
 required_labels = ["regression-from-stable-to-[bn]*"] # only nightly and beta regressions
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "P-high regression #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-high` and is a regression."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+Is issue assigned? If not:
+- Try to find an assignee?
+- Otherwise add to agenda:
+  - Mark as unassigned.
+  - Summary and important details?
+"""