]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #70229 - matthiaskrgr:cl3ppy, r=Mark-Simulacrum
authorDylan DPC <dylan.dpc@gmail.com>
Sun, 22 Mar 2020 14:48:35 +0000 (15:48 +0100)
committerGitHub <noreply@github.com>
Sun, 22 Mar 2020 14:48:35 +0000 (15:48 +0100)
more clippy fixes

* remove unused unit values (clippy::unused_unit)
* make some let-if-bindings more idiomatic (clippy::useless_let_if_seq)
* clarify when we pass () to functions (clippy::unit_arg)
* don't redundantly repeat field names (clippy::redundant_field_names)
* remove redundant returns (clippy::needless_return)
* use let instead of match for matches with single bindings (clippy::match_single_binding)
* don't convert results to options just for matching (clippy::if_let_some_result)

84 files changed:
Cargo.lock
src/bootstrap/bootstrap.py
src/etc/gdb_rust_pretty_printing.py
src/liballoc/rc.rs
src/liballoc/sync.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/query/mod.rs
src/librustc/ty/context.rs
src/librustc/ty/instance.rs
src/librustc/ty/query/caches.rs
src/librustc/ty/query/config.rs
src/librustc/ty/query/mod.rs
src/librustc/ty/query/plumbing.rs
src/librustc/ty/query/profiling_support.rs
src/librustc/ty/query/stats.rs
src/librustc_ast/ast.rs
src/librustc_ast/attr/mod.rs
src/librustc_ast_passes/ast_validation.rs
src/librustc_codegen_ssa/mir/rvalue.rs
src/librustc_error_codes/error_codes.rs
src/librustc_error_codes/error_codes/E0224.md [new file with mode: 0644]
src/librustc_expand/base.rs
src/librustc_expand/expand.rs
src/librustc_infer/infer/error_reporting/mod.rs
src/librustc_infer/infer/mod.rs
src/librustc_interface/passes.rs
src/librustc_mir/interpret/cast.rs
src/librustc_parse/lexer/mod.rs
src/librustc_parse/parser/expr.rs
src/librustc_parse/parser/generics.rs
src/librustc_parse/parser/item.rs
src/librustc_passes/layout_test.rs
src/librustc_span/lib.rs
src/librustc_span/symbol.rs
src/librustc_symbol_mangling/legacy.rs
src/librustc_symbol_mangling/v0.rs
src/librustc_trait_selection/traits/error_reporting/suggestions.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/collect/type_of.rs
src/libstd/error.rs
src/libstd/io/mod.rs
src/libstd/io/stdio.rs
src/libstd/net/addr.rs
src/libstd/sys/cloudabi/mutex.rs
src/libstd/sys/hermit/mutex.rs
src/libstd/sys/sgx/mutex.rs
src/libstd/sys/unix/mutex.rs
src/libstd/sys/vxworks/mutex.rs
src/libstd/sys/wasm/mutex.rs
src/libstd/sys/wasm/mutex_atomics.rs
src/libstd/sys/windows/mutex.rs
src/libstd/sys_common/remutex.rs
src/test/debuginfo/pretty-std-collections.rs
src/test/ui/const-generics/argument_order.rs [new file with mode: 0644]
src/test/ui/const-generics/argument_order.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-66906.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-66906.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-70167.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-70167.stderr [new file with mode: 0644]
src/test/ui/consts/cast-discriminant-zst-enum.rs [new file with mode: 0644]
src/test/ui/eprint-on-tls-drop.rs [new file with mode: 0644]
src/test/ui/issues/issue-70041.rs [new file with mode: 0644]
src/test/ui/issues/issue-70041.stderr [new file with mode: 0644]
src/test/ui/layout/debug.rs [new file with mode: 0644]
src/test/ui/layout/debug.stderr [new file with mode: 0644]
src/test/ui/macros/trace_faulty_macros.rs
src/test/ui/macros/trace_faulty_macros.stderr
src/test/ui/parser/issue-68890-2.stderr
src/test/ui/parser/macro/trait-object-macro-matcher.stderr
src/test/ui/parser/recover-quantified-closure.rs [new file with mode: 0644]
src/test/ui/parser/recover-quantified-closure.stderr [new file with mode: 0644]
src/test/ui/proc-macro/out-of-line-mod.rs [new file with mode: 0644]
src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr
src/test/ui/traits/trait-object-macro-matcher.stderr
src/test/ui/traits/trait-object-vs-lifetime-2.stderr
src/test/ui/traits/trait-object-vs-lifetime.stderr
src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr
src/tools/clippy

index 04044c79bdaf93198a8083cb6e902dfb33612282..5f6cda66ebff1a362341d27727a0a7cca17c386b 100644 (file)
@@ -121,9 +121,9 @@ checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
 
 [[package]]
 name = "backtrace"
-version = "0.3.44"
+version = "0.3.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536"
+checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8"
 dependencies = [
  "backtrace-sys",
  "cfg-if",
@@ -135,9 +135,9 @@ dependencies = [
 
 [[package]]
 name = "backtrace-sys"
-version = "0.1.32"
+version = "0.1.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
+checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69"
 dependencies = [
  "cc",
  "compiler_builtins",
index 50e1726240fffd29936c469d15386e60fad3a52b..d5efed61b541e8fccf24852e4d4a499da6d5fb05 100644 (file)
@@ -664,6 +664,10 @@ class RustBuild(object):
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
         env = os.environ.copy()
+        # `CARGO_BUILD_TARGET` breaks bootstrap build.
+        # See also: <https://github.com/rust-lang/rust/issues/70208>.
+        if "CARGO_BUILD_TARGET" in env:
+            del env["CARGO_BUILD_TARGET"]
         env["RUSTC_BOOTSTRAP"] = '1'
         env["CARGO_TARGET_DIR"] = build_dir
         env["RUSTC"] = self.rustc()
index cae64ef6665bb0b64fc5c827cca265f97c7104dd..51dfc3fff3f92e3c162d8ae933c6e304d82f6128 100755 (executable)
@@ -335,7 +335,7 @@ class RustStdVecDequePrinter(object):
 def children_of_node(boxed_node, height, want_values):
     node_ptr = boxed_node['ptr']['pointer']
     if height > 0:
-        type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode')
+        type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode', 1)
         node_type = gdb.lookup_type(type_name)
         node_ptr = node_ptr.cast(node_type.pointer())
         leaf = node_ptr['data']
index 9c286298aa65cd908d20eb4348bef33fa86d5102..e7f7608e676a203c30505b1004d5a2375656c4a3 100644 (file)
 #[cfg(test)]
 mod tests;
 
+// This is repr(C) to future-proof against possible field-reordering, which
+// would interfere with otherwise safe [into|from]_raw() of transmutable
+// inner types.
+#[repr(C)]
 struct RcBox<T: ?Sized> {
     strong: Cell<usize>,
     weak: Cell<usize>,
@@ -580,15 +584,24 @@ pub fn into_raw(this: Self) -> *const T {
         }
     }
 
-    /// Constructs an `Rc` from a raw pointer.
+    /// Constructs an `Rc<T>` from a raw pointer.
     ///
-    /// The raw pointer must have been previously returned by a call to a
-    /// [`Rc::into_raw`][into_raw].
+    /// The raw pointer must have been previously returned by a call to
+    /// [`Rc<U>::into_raw`][into_raw] where `U` must have the same size
+    /// and alignment as `T`. This is trivially true if `U` is `T`.
+    /// Note that if `U` is not `T` but has the same size and alignment, this is
+    /// basically like transmuting references of different types. See
+    /// [`mem::transmute`][transmute] for more information on what
+    /// restrictions apply in this case.
     ///
-    /// This function is unsafe because improper use may lead to memory problems. For example, a
-    /// double-free may occur if the function is called twice on the same raw pointer.
+    /// The user of `from_raw` has to make sure a specific value of `T` is only
+    /// dropped once.
+    ///
+    /// This function is unsafe because improper use may lead to memory unsafety,
+    /// even if the returned `Rc<T>` is never accessed.
     ///
     /// [into_raw]: struct.Rc.html#method.into_raw
+    /// [transmute]: ../../std/mem/fn.transmute.html
     ///
     /// # Examples
     ///
index d9b54fb0b177ad05a81cc06c52fec3186fc06303..e8985e202567bcd4bd628cfaea34722d32a493f0 100644 (file)
@@ -287,6 +287,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+// This is repr(C) to future-proof against possible field-reordering, which
+// would interfere with otherwise safe [into|from]_raw() of transmutable
+// inner types.
+#[repr(C)]
 struct ArcInner<T: ?Sized> {
     strong: atomic::AtomicUsize,
 
@@ -577,15 +581,24 @@ pub fn into_raw(this: Self) -> *const T {
         }
     }
 
-    /// Constructs an `Arc` from a raw pointer.
+    /// Constructs an `Arc<T>` from a raw pointer.
     ///
-    /// The raw pointer must have been previously returned by a call to a
-    /// [`Arc::into_raw`][into_raw].
+    /// The raw pointer must have been previously returned by a call to
+    /// [`Arc<U>::into_raw`][into_raw] where `U` must have the same size and
+    /// alignment as `T`. This is trivially true if `U` is `T`.
+    /// Note that if `U` is not `T` but has the same size and alignment, this is
+    /// basically like transmuting references of different types. See
+    /// [`mem::transmute`][transmute] for more information on what
+    /// restrictions apply in this case.
     ///
-    /// This function is unsafe because improper use may lead to memory problems. For example, a
-    /// double-free may occur if the function is called twice on the same raw pointer.
+    /// The user of `from_raw` has to make sure a specific value of `T` is only
+    /// dropped once.
+    ///
+    /// This function is unsafe because improper use may lead to memory unsafety,
+    /// even if the returned `Arc<T>` is never accessed.
     ///
     /// [into_raw]: struct.Arc.html#method.into_raw
+    /// [transmute]: ../../std/mem/fn.transmute.html
     ///
     /// # Examples
     ///
index 13257e7bf47701bd6d6013f5d1129e0cd4ced85c..49b7ce3445ba827901fc2cebdca8326e59307ccf 100644 (file)
@@ -337,23 +337,28 @@ pub fn def_kind(&self, hir_id: HirId) -> Option<DefKind> {
     }
 
     fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> {
-        Some(self.get_entry(id))
-    }
-
-    fn get_entry(&self, id: HirId) -> Entry<'hir> {
         if id.local_id == ItemLocalId::from_u32(0) {
             let owner = self.tcx.hir_owner(id.owner);
-            Entry { parent: owner.parent, node: owner.node }
+            owner.map(|owner| Entry { parent: owner.parent, node: owner.node })
         } else {
             let owner = self.tcx.hir_owner_nodes(id.owner);
-            let node = owner.nodes[id.local_id].as_ref().unwrap();
-            // FIXME(eddyb) use a single generic type insted of having both
-            // `Entry` and `ParentedNode`, which are effectively the same.
-            // Alternatively, rewrite code using `Entry` to use `ParentedNode`.
-            Entry { parent: HirId { owner: id.owner, local_id: node.parent }, node: node.node }
+            owner.and_then(|owner| {
+                let node = owner.nodes[id.local_id].as_ref();
+                // FIXME(eddyb) use a single generic type insted of having both
+                // `Entry` and `ParentedNode`, which are effectively the same.
+                // Alternatively, rewrite code using `Entry` to use `ParentedNode`.
+                node.map(|node| Entry {
+                    parent: HirId { owner: id.owner, local_id: node.parent },
+                    node: node.node,
+                })
+            })
         }
     }
 
+    fn get_entry(&self, id: HirId) -> Entry<'hir> {
+        self.find_entry(id).unwrap()
+    }
+
     pub fn item(&self, id: HirId) -> &'hir Item<'hir> {
         match self.find(id).unwrap() {
             Node::Item(item) => item,
@@ -376,7 +381,7 @@ pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
     }
 
     pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
-        self.tcx.hir_owner_nodes(id.hir_id.owner).bodies.get(&id.hir_id.local_id).unwrap()
+        self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap()
     }
 
     pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
@@ -536,8 +541,9 @@ pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
 
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
     pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
-        let node = self.get_entry(hir_id).node;
-        if let Node::Crate(..) = node { None } else { Some(node) }
+        self.find_entry(hir_id).and_then(|entry| {
+            if let Node::Crate(..) = entry.node { None } else { Some(entry.node) }
+        })
     }
 
     /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there
index d9dfd2961ff17508e73e4947caaee7b9b7fcbd38..ce8e1f48daa77dcf5c0e925b90e743c3a7dca14b 100644 (file)
@@ -78,9 +78,8 @@ pub fn provide(providers: &mut Providers<'_>) {
         let module = hir.as_local_hir_id(id.to_def_id()).unwrap();
         &tcx.untracked_crate.modules[&module]
     };
-    providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature.unwrap();
-    providers.hir_owner_nodes = |tcx, id| {
-        tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_ref().map(|nodes| &**nodes).unwrap()
-    };
+    providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
+    providers.hir_owner_nodes =
+        |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_ref().map(|nodes| &**nodes);
     map::provide(providers);
 }
index 00e40faa95c304fef90503e99be88ec9a4c0586e..54f5103f736ec07875cb2174d5176415dbf0e1e8 100644 (file)
@@ -76,7 +76,7 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
         //
         // This can be conveniently accessed by methods on `tcx.hir()`.
         // Avoid calling this query directly.
-        query hir_owner(key: LocalDefId) -> &'tcx crate::hir::Owner<'tcx> {
+        query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> {
             eval_always
             desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
         }
@@ -85,7 +85,7 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
         //
         // This can be conveniently accessed by methods on `tcx.hir()`.
         // Avoid calling this query directly.
-        query hir_owner_nodes(key: LocalDefId) -> &'tcx crate::hir::OwnerNodes<'tcx> {
+        query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> {
             eval_always
             desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
         }
index 9b67d4235102d7d7df72e61e74662199c286181d..75842fd554941fb8d4d5be581a75d6a1a7bd7f6b 100644 (file)
@@ -188,37 +188,37 @@ pub struct CommonConsts<'tcx> {
 }
 
 pub struct LocalTableInContext<'a, V> {
-    local_id_root: Option<DefId>,
+    hir_owner: Option<LocalDefId>,
     data: &'a ItemLocalMap<V>,
 }
 
 /// Validate that the given HirId (respectively its `local_id` part) can be
 /// safely used as a key in the tables of a TypeckTable. For that to be
 /// the case, the HirId must have the same `owner` as all the other IDs in
-/// this table (signified by `local_id_root`). Otherwise the HirId
+/// this table (signified by `hir_owner`). Otherwise the HirId
 /// would be in a different frame of reference and using its `local_id`
 /// would result in lookup errors, or worse, in silently wrong data being
 /// stored/returned.
 fn validate_hir_id_for_typeck_tables(
-    local_id_root: Option<DefId>,
+    hir_owner: Option<LocalDefId>,
     hir_id: hir::HirId,
     mut_access: bool,
 ) {
-    if let Some(local_id_root) = local_id_root {
-        if hir_id.owner.to_def_id() != local_id_root {
+    if let Some(hir_owner) = hir_owner {
+        if hir_id.owner != hir_owner {
             ty::tls::with(|tcx| {
                 bug!(
                     "node {} with HirId::owner {:?} cannot be placed in \
-                     TypeckTables with local_id_root {:?}",
+                     TypeckTables with hir_owner {:?}",
                     tcx.hir().node_to_string(hir_id),
                     hir_id.owner,
-                    local_id_root
+                    hir_owner
                 )
             });
         }
     } else {
         // We use "Null Object" TypeckTables in some of the analysis passes.
-        // These are just expected to be empty and their `local_id_root` is
+        // These are just expected to be empty and their `hir_owner` is
         // `None`. Therefore we cannot verify whether a given `HirId` would
         // be a valid key for the given table. Instead we make sure that
         // nobody tries to write to such a Null Object table.
@@ -230,12 +230,12 @@ fn validate_hir_id_for_typeck_tables(
 
 impl<'a, V> LocalTableInContext<'a, V> {
     pub fn contains_key(&self, id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, false);
         self.data.contains_key(&id.local_id)
     }
 
     pub fn get(&self, id: hir::HirId) -> Option<&V> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, false);
         self.data.get(&id.local_id)
     }
 
@@ -253,28 +253,28 @@ fn index(&self, key: hir::HirId) -> &V {
 }
 
 pub struct LocalTableInContextMut<'a, V> {
-    local_id_root: Option<DefId>,
+    hir_owner: Option<LocalDefId>,
     data: &'a mut ItemLocalMap<V>,
 }
 
 impl<'a, V> LocalTableInContextMut<'a, V> {
     pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, true);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, true);
         self.data.get_mut(&id.local_id)
     }
 
     pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, true);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, true);
         self.data.entry(id.local_id)
     }
 
     pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, true);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, true);
         self.data.insert(id.local_id, val)
     }
 
     pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, true);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, true);
         self.data.remove(&id.local_id)
     }
 }
@@ -322,8 +322,8 @@ pub struct GeneratorInteriorTypeCause<'tcx> {
 
 #[derive(RustcEncodable, RustcDecodable, Debug)]
 pub struct TypeckTables<'tcx> {
-    /// The HirId::owner all ItemLocalIds in this table are relative to.
-    pub local_id_root: Option<DefId>,
+    /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
+    pub hir_owner: Option<LocalDefId>,
 
     /// Resolved definitions for `<T>::X` associated paths and
     /// method calls, including those of overloaded operators.
@@ -431,9 +431,9 @@ pub struct TypeckTables<'tcx> {
 }
 
 impl<'tcx> TypeckTables<'tcx> {
-    pub fn empty(local_id_root: Option<DefId>) -> TypeckTables<'tcx> {
+    pub fn empty(hir_owner: Option<LocalDefId>) -> TypeckTables<'tcx> {
         TypeckTables {
-            local_id_root,
+            hir_owner,
             type_dependent_defs: Default::default(),
             field_indices: Default::default(),
             user_provided_types: Default::default(),
@@ -469,11 +469,11 @@ pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
     pub fn type_dependent_defs(
         &self,
     ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorReported>> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.type_dependent_defs }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
     }
 
     pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, false);
         self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
     }
 
@@ -484,39 +484,33 @@ pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
     pub fn type_dependent_defs_mut(
         &mut self,
     ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorReported>> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.type_dependent_defs,
-        }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
     }
 
     pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.field_indices }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
     }
 
     pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
-        LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.field_indices }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
     }
 
     pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.user_provided_types }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
     }
 
     pub fn user_provided_types_mut(
         &mut self,
     ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.user_provided_types,
-        }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
     }
 
     pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.node_types }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
     }
 
     pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
-        LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.node_types }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
     }
 
     pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
@@ -526,21 +520,21 @@ pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
     }
 
     pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, false);
         self.node_types.get(&id.local_id).cloned()
     }
 
     pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
-        LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.node_substs }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
     }
 
     pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, false);
         self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
     }
 
     pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
+        validate_hir_id_for_typeck_tables(self.hir_owner, id, false);
         self.node_substs.get(&id.local_id).cloned()
     }
 
@@ -573,17 +567,17 @@ pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
     }
 
     pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.adjustments }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments }
     }
 
     pub fn adjustments_mut(
         &mut self,
     ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
-        LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.adjustments }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
     }
 
     pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
-        validate_hir_id_for_typeck_tables(self.local_id_root, expr.hir_id, false);
+        validate_hir_id_for_typeck_tables(self.hir_owner, expr.hir_id, false);
         self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
     }
 
@@ -618,25 +612,19 @@ pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<B
     }
 
     pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.pat_binding_modes }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
     }
 
     pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.pat_binding_modes,
-        }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
     }
 
     pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.pat_adjustments }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
     }
 
     pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.pat_adjustments,
-        }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
     }
 
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
@@ -644,40 +632,31 @@ pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
     }
 
     pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, ast::Name)> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.closure_kind_origins }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
     }
 
     pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<'_, (Span, ast::Name)> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.closure_kind_origins,
-        }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
     }
 
     pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.liberated_fn_sigs }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
     }
 
     pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.liberated_fn_sigs,
-        }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
     }
 
     pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContext { local_id_root: self.local_id_root, data: &self.fru_field_types }
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
     }
 
     pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.fru_field_types,
-        }
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
     }
 
     pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_tables(self.local_id_root, hir_id, true);
+        validate_hir_id_for_typeck_tables(self.hir_owner, hir_id, true);
         self.coercion_casts.contains(&hir_id.local_id)
     }
 
@@ -693,7 +672,7 @@ pub fn coercion_casts(&self) -> &ItemLocalSet {
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         let ty::TypeckTables {
-            local_id_root,
+            hir_owner,
             ref type_dependent_defs,
             ref field_indices,
             ref user_provided_types,
@@ -730,18 +709,12 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
             hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| {
                 let ty::UpvarId { var_path, closure_expr_id } = *up_var_id;
 
-                let local_id_root = local_id_root.expect("trying to hash invalid TypeckTables");
+                assert_eq!(Some(var_path.hir_id.owner), hir_owner);
 
-                let var_owner_def_id = DefId {
-                    krate: local_id_root.krate,
-                    index: var_path.hir_id.owner.local_def_index,
-                };
-                let closure_def_id =
-                    DefId { krate: local_id_root.krate, index: closure_expr_id.local_def_index };
                 (
-                    hcx.def_path_hash(var_owner_def_id),
+                    hcx.local_def_path_hash(var_path.hir_id.owner),
                     var_path.hir_id.local_id,
-                    hcx.def_path_hash(closure_def_id),
+                    hcx.local_def_path_hash(closure_expr_id),
                 )
             });
 
index 13d58ea73ac6b9074b8d93b09301d67479997e36..46372701a92544eec022aed942edc5b584df7d54 100644 (file)
@@ -406,10 +406,6 @@ pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
             | InstanceDef::VtableShim(..) => Some(self.substs),
         }
     }
-
-    pub fn is_vtable_shim(&self) -> bool {
-        if let InstanceDef::VtableShim(..) = self.def { true } else { false }
-    }
 }
 
 fn needs_fn_once_adapter_shim(
index efc2804bd4d5985fa45b1fc95a19c05b18dc6501..a11b3bcba3ed30dc7e8774f8e200e3db01ca1e9c 100644 (file)
@@ -1,5 +1,4 @@
 use crate::dep_graph::DepNodeIndex;
-use crate::ty::query::config::QueryAccessors;
 use crate::ty::query::plumbing::{QueryLookup, QueryState, QueryStateShard};
 use crate::ty::TyCtxt;
 
@@ -7,39 +6,43 @@
 use rustc_data_structures::sharded::Sharded;
 use std::default::Default;
 use std::hash::Hash;
+use std::marker::PhantomData;
 
 pub(crate) trait CacheSelector<K, V> {
-    type Cache: QueryCache<K, V>;
+    type Cache: QueryCache<Key = K, Value = V>;
 }
 
-pub(crate) trait QueryCache<K, V>: Default {
+pub(crate) trait QueryCache: Default {
+    type Key;
+    type Value;
     type Sharded: Default;
 
     /// Checks if the query is already computed and in the cache.
     /// It returns the shard index and a lock guard to the shard,
     /// which will be used if the query is not in the cache and we need
     /// to compute it.
-    fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>(
+    fn lookup<'tcx, R, GetCache, OnHit, OnMiss>(
         &self,
-        state: &'tcx QueryState<'tcx, Q>,
+        state: &'tcx QueryState<'tcx, Self>,
         get_cache: GetCache,
-        key: K,
+        key: Self::Key,
         // `on_hit` can be called while holding a lock to the query state shard.
         on_hit: OnHit,
         on_miss: OnMiss,
     ) -> R
     where
-        Q: QueryAccessors<'tcx>,
-        GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded,
-        OnHit: FnOnce(&V, DepNodeIndex) -> R,
-        OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R;
+        GetCache: for<'a> Fn(
+            &'a mut QueryStateShard<'tcx, Self::Key, Self::Sharded>,
+        ) -> &'a mut Self::Sharded,
+        OnHit: FnOnce(&Self::Value, DepNodeIndex) -> R,
+        OnMiss: FnOnce(Self::Key, QueryLookup<'tcx, Self::Key, Self::Sharded>) -> R;
 
     fn complete(
         &self,
         tcx: TyCtxt<'tcx>,
         lock_sharded_storage: &mut Self::Sharded,
-        key: K,
-        value: V,
+        key: Self::Key,
+        value: Self::Value,
         index: DepNodeIndex,
     );
 
@@ -47,36 +50,45 @@ fn iter<R, L>(
         &self,
         shards: &Sharded<L>,
         get_shard: impl Fn(&mut L) -> &mut Self::Sharded,
-        f: impl for<'a> FnOnce(Box<dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)> + 'a>) -> R,
+        f: impl for<'a> FnOnce(
+            Box<dyn Iterator<Item = (&'a Self::Key, &'a Self::Value, DepNodeIndex)> + 'a>,
+        ) -> R,
     ) -> R;
 }
 
 pub struct DefaultCacheSelector;
 
 impl<K: Eq + Hash, V: Clone> CacheSelector<K, V> for DefaultCacheSelector {
-    type Cache = DefaultCache;
+    type Cache = DefaultCache<K, V>;
 }
 
-#[derive(Default)]
-pub struct DefaultCache;
+pub struct DefaultCache<K, V>(PhantomData<(K, V)>);
+
+impl<K, V> Default for DefaultCache<K, V> {
+    fn default() -> Self {
+        DefaultCache(PhantomData)
+    }
+}
 
-impl<K: Eq + Hash, V: Clone> QueryCache<K, V> for DefaultCache {
+impl<K: Eq + Hash, V: Clone> QueryCache for DefaultCache<K, V> {
+    type Key = K;
+    type Value = V;
     type Sharded = FxHashMap<K, (V, DepNodeIndex)>;
 
     #[inline(always)]
-    fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>(
+    fn lookup<'tcx, R, GetCache, OnHit, OnMiss>(
         &self,
-        state: &'tcx QueryState<'tcx, Q>,
+        state: &'tcx QueryState<'tcx, Self>,
         get_cache: GetCache,
         key: K,
         on_hit: OnHit,
         on_miss: OnMiss,
     ) -> R
     where
-        Q: QueryAccessors<'tcx>,
-        GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded,
+        GetCache:
+            for<'a> Fn(&'a mut QueryStateShard<'tcx, K, Self::Sharded>) -> &'a mut Self::Sharded,
         OnHit: FnOnce(&V, DepNodeIndex) -> R,
-        OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R,
+        OnMiss: FnOnce(K, QueryLookup<'tcx, K, Self::Sharded>) -> R,
     {
         let mut lookup = state.get_lookup(&key);
         let lock = &mut *lookup.lock;
index 178c2362def6e9db554cbdef6f8c67c63c2048f5..72a0fdf1567268f03338dbd0db6afc97ad70fb85 100644 (file)
@@ -2,7 +2,7 @@
 use crate::dep_graph::{DepKind, DepNode};
 use crate::ty::query::caches::QueryCache;
 use crate::ty::query::plumbing::CycleError;
-use crate::ty::query::{Query, QueryState};
+use crate::ty::query::QueryState;
 use crate::ty::TyCtxt;
 use rustc_data_structures::profiling::ProfileCategory;
 use rustc_hir::def_id::DefId;
@@ -28,18 +28,15 @@ pub trait QueryConfig<'tcx> {
 pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> {
     const ANON: bool;
     const EVAL_ALWAYS: bool;
+    const DEP_KIND: DepKind;
 
-    type Cache: QueryCache<Self::Key, Self::Value>;
-
-    fn query(key: Self::Key) -> Query<'tcx>;
+    type Cache: QueryCache<Key = Self::Key, Value = Self::Value>;
 
     // Don't use this method to access query results, instead use the methods on TyCtxt
-    fn query_state<'a>(tcx: TyCtxt<'tcx>) -> &'a QueryState<'tcx, Self>;
+    fn query_state<'a>(tcx: TyCtxt<'tcx>) -> &'a QueryState<'tcx, Self::Cache>;
 
     fn to_dep_node(tcx: TyCtxt<'tcx>, key: &Self::Key) -> DepNode;
 
-    fn dep_kind() -> DepKind;
-
     // Don't use this method to compute query results, instead use the methods on TyCtxt
     fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value;
 
@@ -62,10 +59,7 @@ fn try_load_from_disk(_: TyCtxt<'tcx>, _: SerializedDepNodeIndex) -> Option<Self
     }
 }
 
-impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M
-where
-    <M as QueryAccessors<'tcx>>::Cache: QueryCache<DefId, <M as QueryConfig<'tcx>>::Value>,
-{
+impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M {
     default fn describe(tcx: TyCtxt<'_>, def_id: DefId) -> Cow<'static, str> {
         if !tcx.sess.verbose() {
             format!("processing `{}`", tcx.def_path_str(def_id)).into()
index 11bedc82eb7d74ff4b41528ad0704079eb99daec..32ba13b1dbe9a5cfe2740383518400befde1ad28 100644 (file)
 use rustc_span::{Span, DUMMY_SP};
 use std::borrow::Cow;
 use std::collections::BTreeMap;
-use std::convert::TryFrom;
 use std::ops::Deref;
 use std::sync::Arc;
 
 #[macro_use]
 mod plumbing;
-pub use self::plumbing::CycleError;
+pub(crate) use self::plumbing::CycleError;
 use self::plumbing::*;
 
 mod stats;
index 3d59fc782113b26751a49614f461afe4aaa1a72b..80a4e552f02d6101cd7fbd413d30b29aa8951497 100644 (file)
@@ -2,10 +2,10 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
+use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
 use crate::ty::query::caches::QueryCache;
-use crate::ty::query::config::{QueryAccessors, QueryDescription};
-use crate::ty::query::job::{QueryInfo, QueryJob, QueryJobId, QueryShardJobId};
+use crate::ty::query::config::QueryDescription;
+use crate::ty::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId};
 use crate::ty::query::Query;
 use crate::ty::tls;
 use crate::ty::{self, TyCtxt};
@@ -20,6 +20,8 @@
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::Span;
 use std::collections::hash_map::Entry;
+use std::convert::TryFrom;
+use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::num::NonZeroU32;
 #[cfg(debug_assertions)]
 use std::sync::atomic::{AtomicUsize, Ordering};
 
-pub(crate) struct QueryStateShard<'tcx, D: QueryAccessors<'tcx> + ?Sized> {
-    pub(super) cache: <<D as QueryAccessors<'tcx>>::Cache as QueryCache<D::Key, D::Value>>::Sharded,
-    pub(super) active: FxHashMap<D::Key, QueryResult<'tcx>>,
+pub(crate) struct QueryStateShard<'tcx, K, C> {
+    cache: C,
+    active: FxHashMap<K, QueryResult<'tcx>>,
 
     /// Used to generate unique ids for active jobs.
-    pub(super) jobs: u32,
+    jobs: u32,
 }
 
-impl<'tcx, Q: QueryAccessors<'tcx>> QueryStateShard<'tcx, Q> {
-    fn get_cache(
-        &mut self,
-    ) -> &mut <<Q as QueryAccessors<'tcx>>::Cache as QueryCache<Q::Key, Q::Value>>::Sharded {
+impl<'tcx, K, C> QueryStateShard<'tcx, K, C> {
+    fn get_cache(&mut self) -> &mut C {
         &mut self.cache
     }
 }
 
-impl<'tcx, Q: QueryAccessors<'tcx>> Default for QueryStateShard<'tcx, Q> {
-    fn default() -> QueryStateShard<'tcx, Q> {
+impl<'tcx, K, C: Default> Default for QueryStateShard<'tcx, K, C> {
+    fn default() -> QueryStateShard<'tcx, K, C> {
         QueryStateShard { cache: Default::default(), active: Default::default(), jobs: 0 }
     }
 }
 
-pub(crate) struct QueryState<'tcx, D: QueryAccessors<'tcx> + ?Sized> {
-    pub(super) cache: D::Cache,
-    pub(super) shards: Sharded<QueryStateShard<'tcx, D>>,
+pub(crate) struct QueryState<'tcx, C: QueryCache> {
+    cache: C,
+    shards: Sharded<QueryStateShard<'tcx, C::Key, C::Sharded>>,
     #[cfg(debug_assertions)]
     pub(super) cache_hits: AtomicUsize,
 }
 
-impl<'tcx, Q: QueryAccessors<'tcx>> QueryState<'tcx, Q> {
-    pub(super) fn get_lookup<K: Hash>(&'tcx self, key: &K) -> QueryLookup<'tcx, Q> {
+impl<'tcx, C: QueryCache> QueryState<'tcx, C> {
+    pub(super) fn get_lookup<K2: Hash>(
+        &'tcx self,
+        key: &K2,
+    ) -> QueryLookup<'tcx, C::Key, C::Sharded> {
         // We compute the key's hash once and then use it for both the
         // shard lookup and the hashmap lookup. This relies on the fact
         // that both of them use `FxHasher`.
@@ -72,7 +75,7 @@ pub(super) fn get_lookup<K: Hash>(&'tcx self, key: &K) -> QueryLookup<'tcx, Q> {
 }
 
 /// Indicates the state of a query for a given key in a query map.
-pub(super) enum QueryResult<'tcx> {
+enum QueryResult<'tcx> {
     /// An already executing query. The query job can be used to await for its completion.
     Started(QueryJob<'tcx>),
 
@@ -81,25 +84,54 @@ pub(super) enum QueryResult<'tcx> {
     Poisoned,
 }
 
-impl<'tcx, M: QueryAccessors<'tcx>> QueryState<'tcx, M> {
-    pub fn iter_results<R>(
+impl<'tcx, C: QueryCache> QueryState<'tcx, C> {
+    pub(super) fn iter_results<R>(
         &self,
         f: impl for<'a> FnOnce(
-            Box<dyn Iterator<Item = (&'a M::Key, &'a M::Value, DepNodeIndex)> + 'a>,
+            Box<dyn Iterator<Item = (&'a C::Key, &'a C::Value, DepNodeIndex)> + 'a>,
         ) -> R,
     ) -> R {
         self.cache.iter(&self.shards, |shard| &mut shard.cache, f)
     }
-    pub fn all_inactive(&self) -> bool {
+    pub(super) fn all_inactive(&self) -> bool {
         let shards = self.shards.lock_shards();
         shards.iter().all(|shard| shard.active.is_empty())
     }
+
+    pub(super) fn try_collect_active_jobs(
+        &self,
+        kind: DepKind,
+        make_query: fn(C::Key) -> Query<'tcx>,
+        jobs: &mut FxHashMap<QueryJobId, QueryJobInfo<'tcx>>,
+    ) -> Option<()>
+    where
+        C::Key: Clone,
+    {
+        // We use try_lock_shards here since we are called from the
+        // deadlock handler, and this shouldn't be locked.
+        let shards = self.shards.try_lock_shards()?;
+        let shards = shards.iter().enumerate();
+        jobs.extend(shards.flat_map(|(shard_id, shard)| {
+            shard.active.iter().filter_map(move |(k, v)| {
+                if let QueryResult::Started(ref job) = *v {
+                    let id =
+                        QueryJobId { job: job.id, shard: u16::try_from(shard_id).unwrap(), kind };
+                    let info = QueryInfo { span: job.span, query: make_query(k.clone()) };
+                    Some((id, QueryJobInfo { info, job: job.clone() }))
+                } else {
+                    None
+                }
+            })
+        }));
+
+        Some(())
+    }
 }
 
-impl<'tcx, M: QueryAccessors<'tcx>> Default for QueryState<'tcx, M> {
-    fn default() -> QueryState<'tcx, M> {
+impl<'tcx, C: QueryCache> Default for QueryState<'tcx, C> {
+    fn default() -> QueryState<'tcx, C> {
         QueryState {
-            cache: M::Cache::default(),
+            cache: C::default(),
             shards: Default::default(),
             #[cfg(debug_assertions)]
             cache_hits: AtomicUsize::new(0),
@@ -108,21 +140,31 @@ fn default() -> QueryState<'tcx, M> {
 }
 
 /// Values used when checking a query cache which can be reused on a cache-miss to execute the query.
-pub(crate) struct QueryLookup<'tcx, Q: QueryAccessors<'tcx>> {
+pub(crate) struct QueryLookup<'tcx, K, C> {
     pub(super) key_hash: u64,
-    pub(super) shard: usize,
-    pub(super) lock: LockGuard<'tcx, QueryStateShard<'tcx, Q>>,
+    shard: usize,
+    pub(super) lock: LockGuard<'tcx, QueryStateShard<'tcx, K, C>>,
 }
 
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
-pub(super) struct JobOwner<'tcx, Q: QueryDescription<'tcx>> {
-    tcx: TyCtxt<'tcx>,
-    key: Q::Key,
+struct JobOwner<'tcx, C>
+where
+    C: QueryCache,
+    C::Key: Eq + Hash + Clone + Debug,
+    C::Value: Clone,
+{
+    state: &'tcx QueryState<'tcx, C>,
+    key: C::Key,
     id: QueryJobId,
 }
 
-impl<'tcx, Q: QueryDescription<'tcx>> JobOwner<'tcx, Q> {
+impl<'tcx, C: QueryCache> JobOwner<'tcx, C>
+where
+    C: QueryCache,
+    C::Key: Eq + Hash + Clone + Debug,
+    C::Value: Clone,
+{
     /// Either gets a `JobOwner` corresponding the query, allowing us to
     /// start executing the query, or returns with the result of the query.
     /// This function assumes that `try_get_cached` is already called and returned `lookup`.
@@ -132,12 +174,15 @@ impl<'tcx, Q: QueryDescription<'tcx>> JobOwner<'tcx, Q> {
     /// This function is inlined because that results in a noticeable speed-up
     /// for some compile-time benchmarks.
     #[inline(always)]
-    pub(super) fn try_start(
+    fn try_start<Q>(
         tcx: TyCtxt<'tcx>,
         span: Span,
-        key: &Q::Key,
-        mut lookup: QueryLookup<'tcx, Q>,
-    ) -> TryGetJob<'tcx, Q> {
+        key: &C::Key,
+        mut lookup: QueryLookup<'tcx, C::Key, C::Sharded>,
+    ) -> TryGetJob<'tcx, C>
+    where
+        Q: QueryDescription<'tcx, Key = C::Key, Value = C::Value, Cache = C>,
+    {
         let lock = &mut *lookup.lock;
 
         let (latch, mut _query_blocked_prof_timer) = match lock.active.entry((*key).clone()) {
@@ -154,7 +199,7 @@ pub(super) fn try_start(
                         };
 
                         // Create the id of the job we're waiting for
-                        let id = QueryJobId::new(job.id, lookup.shard, Q::dep_kind());
+                        let id = QueryJobId::new(job.id, lookup.shard, Q::DEP_KIND);
 
                         (job.latch(id), _query_blocked_prof_timer)
                     }
@@ -169,13 +214,14 @@ pub(super) fn try_start(
                 lock.jobs = id;
                 let id = QueryShardJobId(NonZeroU32::new(id).unwrap());
 
-                let global_id = QueryJobId::new(id, lookup.shard, Q::dep_kind());
+                let global_id = QueryJobId::new(id, lookup.shard, Q::DEP_KIND);
 
                 let job = tls::with_related_context(tcx, |icx| QueryJob::new(id, span, icx.query));
 
                 entry.insert(QueryResult::Started(job));
 
-                let owner = JobOwner { tcx, id: global_id, key: (*key).clone() };
+                let owner =
+                    JobOwner { state: Q::query_state(tcx), id: global_id, key: (*key).clone() };
                 return TryGetJob::NotYetStarted(owner);
             }
         };
@@ -198,7 +244,8 @@ pub(super) fn try_start(
                 return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle));
             }
 
-            let cached = tcx.try_get_cached::<Q, _, _, _>(
+            let cached = tcx.try_get_cached(
+                Q::query_state(tcx),
                 (*key).clone(),
                 |value, index| (value.clone(), index),
                 |_, _| panic!("value must be in cache after waiting"),
@@ -215,16 +262,15 @@ pub(super) fn try_start(
     /// Completes the query by updating the query cache with the `result`,
     /// signals the waiter and forgets the JobOwner, so it won't poison the query
     #[inline(always)]
-    pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) {
+    fn complete(self, tcx: TyCtxt<'tcx>, result: &C::Value, dep_node_index: DepNodeIndex) {
         // We can move out of `self` here because we `mem::forget` it below
         let key = unsafe { ptr::read(&self.key) };
-        let tcx = self.tcx;
+        let state = self.state;
 
         // Forget ourself so our destructor won't poison the query
         mem::forget(self);
 
         let job = {
-            let state = Q::query_state(tcx);
             let result = result.clone();
             let mut lock = state.shards.get_shard_by_value(&key).lock();
             let job = match lock.active.remove(&key).unwrap() {
@@ -249,12 +295,16 @@ fn with_diagnostics<F, R>(f: F) -> (R, ThinVec<Diagnostic>)
     (result, diagnostics.into_inner())
 }
 
-impl<'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'tcx, Q> {
+impl<'tcx, C: QueryCache> Drop for JobOwner<'tcx, C>
+where
+    C::Key: Eq + Hash + Clone + Debug,
+    C::Value: Clone,
+{
     #[inline(never)]
     #[cold]
     fn drop(&mut self) {
         // Poison the query so jobs waiting on it panic.
-        let state = Q::query_state(self.tcx);
+        let state = self.state;
         let shard = state.shards.get_shard_by_value(&self.key);
         let job = {
             let mut shard = shard.lock();
@@ -272,25 +322,29 @@ fn drop(&mut self) {
 }
 
 #[derive(Clone)]
-pub struct CycleError<'tcx> {
+pub(crate) struct CycleError<'tcx> {
     /// The query and related span that uses the cycle.
     pub(super) usage: Option<(Span, Query<'tcx>)>,
     pub(super) cycle: Vec<QueryInfo<'tcx>>,
 }
 
 /// The result of `try_start`.
-pub(super) enum TryGetJob<'tcx, D: QueryDescription<'tcx>> {
+enum TryGetJob<'tcx, C: QueryCache>
+where
+    C::Key: Eq + Hash + Clone + Debug,
+    C::Value: Clone,
+{
     /// The query is not yet started. Contains a guard to the cache eventually used to start it.
-    NotYetStarted(JobOwner<'tcx, D>),
+    NotYetStarted(JobOwner<'tcx, C>),
 
     /// The query was already completed.
     /// Returns the result of the query and its dep-node index
     /// if it succeeded or a cycle error if it failed.
     #[cfg(parallel_compiler)]
-    JobCompleted((D::Value, DepNodeIndex)),
+    JobCompleted((C::Value, DepNodeIndex)),
 
     /// Trying to execute the query resulted in a cycle.
-    Cycle(D::Value),
+    Cycle(C::Value),
 }
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -298,7 +352,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// new query job while it executes. It returns the diagnostics
     /// captured during execution and the actual result.
     #[inline(always)]
-    pub(super) fn start_query<F, R>(
+    fn start_query<F, R>(
         self,
         token: QueryJobId,
         diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
@@ -419,23 +473,22 @@ pub fn try_print_query_stack(handler: &Handler) {
     /// which will be used if the query is not in the cache and we need
     /// to compute it.
     #[inline(always)]
-    fn try_get_cached<Q, R, OnHit, OnMiss>(
+    fn try_get_cached<C, R, OnHit, OnMiss>(
         self,
-        key: Q::Key,
+        state: &'tcx QueryState<'tcx, C>,
+        key: C::Key,
         // `on_hit` can be called while holding a lock to the query cache
         on_hit: OnHit,
         on_miss: OnMiss,
     ) -> R
     where
-        Q: QueryDescription<'tcx> + 'tcx,
-        OnHit: FnOnce(&Q::Value, DepNodeIndex) -> R,
-        OnMiss: FnOnce(Q::Key, QueryLookup<'tcx, Q>) -> R,
+        C: QueryCache,
+        OnHit: FnOnce(&C::Value, DepNodeIndex) -> R,
+        OnMiss: FnOnce(C::Key, QueryLookup<'tcx, C::Key, C::Sharded>) -> R,
     {
-        let state = Q::query_state(self);
-
         state.cache.lookup(
             state,
-            QueryStateShard::<Q>::get_cache,
+            QueryStateShard::<C::Key, C::Sharded>::get_cache,
             key,
             |value, index| {
                 if unlikely!(self.prof.enabled()) {
@@ -459,7 +512,8 @@ pub(super) fn get_query<Q: QueryDescription<'tcx> + 'tcx>(
     ) -> Q::Value {
         debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
 
-        self.try_get_cached::<Q, _, _, _>(
+        self.try_get_cached(
+            Q::query_state(self),
             key,
             |value, index| {
                 self.dep_graph.read_index(index);
@@ -470,13 +524,13 @@ pub(super) fn get_query<Q: QueryDescription<'tcx> + 'tcx>(
     }
 
     #[inline(always)]
-    pub(super) fn try_execute_query<Q: QueryDescription<'tcx>>(
+    fn try_execute_query<Q: QueryDescription<'tcx> + 'tcx>(
         self,
         span: Span,
         key: Q::Key,
-        lookup: QueryLookup<'tcx, Q>,
+        lookup: QueryLookup<'tcx, Q::Key, <Q::Cache as QueryCache>::Sharded>,
     ) -> Q::Value {
-        let job = match JobOwner::try_start(self, span, &key, lookup) {
+        let job = match JobOwner::try_start::<Q>(self, span, &key, lookup) {
             TryGetJob::NotYetStarted(job) => job,
             TryGetJob::Cycle(result) => return result,
             #[cfg(parallel_compiler)]
@@ -498,7 +552,7 @@ pub(super) fn try_execute_query<Q: QueryDescription<'tcx>>(
 
             let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
                 self.start_query(job.id, diagnostics, |tcx| {
-                    tcx.dep_graph.with_anon_task(Q::dep_kind(), || Q::compute(tcx, key))
+                    tcx.dep_graph.with_anon_task(Q::DEP_KIND, || Q::compute(tcx, key))
                 })
             });
 
@@ -512,7 +566,7 @@ pub(super) fn try_execute_query<Q: QueryDescription<'tcx>>(
                     .store_diagnostics_for_anon_node(dep_node_index, diagnostics);
             }
 
-            job.complete(&result, dep_node_index);
+            job.complete(self, &result, dep_node_index);
 
             return result;
         }
@@ -538,7 +592,7 @@ pub(super) fn try_execute_query<Q: QueryDescription<'tcx>>(
                 })
             });
             if let Some((result, dep_node_index)) = loaded {
-                job.complete(&result, dep_node_index);
+                job.complete(self, &result, dep_node_index);
                 return result;
             }
         }
@@ -634,10 +688,10 @@ fn incremental_verify_ich<Q: QueryDescription<'tcx>>(
     }
 
     #[inline(always)]
-    fn force_query_with_job<Q: QueryDescription<'tcx>>(
+    fn force_query_with_job<Q: QueryDescription<'tcx> + 'tcx>(
         self,
         key: Q::Key,
-        job: JobOwner<'tcx, Q>,
+        job: JobOwner<'tcx, Q::Cache>,
         dep_node: DepNode,
     ) -> (Q::Value, DepNodeIndex) {
         // If the following assertion triggers, it can have two reasons:
@@ -680,7 +734,7 @@ fn force_query_with_job<Q: QueryDescription<'tcx>>(
             }
         }
 
-        job.complete(&result, dep_node_index);
+        job.complete(self, &result, dep_node_index);
 
         (result, dep_node_index)
     }
@@ -729,13 +783,14 @@ pub(super) fn force_query<Q: QueryDescription<'tcx> + 'tcx>(
         // We may be concurrently trying both execute and force a query.
         // Ensure that only one of them runs the query.
 
-        self.try_get_cached::<Q, _, _, _>(
+        self.try_get_cached(
+            Q::query_state(self),
             key,
             |_, _| {
                 // Cache hit, do nothing
             },
             |key, lookup| {
-                let job = match JobOwner::try_start(self, span, &key, lookup) {
+                let job = match JobOwner::try_start::<Q>(self, span, &key, lookup) {
                     TryGetJob::NotYetStarted(job) => job,
                     TryGetJob::Cycle(_) => return,
                     #[cfg(parallel_compiler)]
@@ -842,55 +897,6 @@ macro_rules! define_queries_inner {
             input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
         }
 
-        impl<$tcx> Queries<$tcx> {
-            pub fn new(
-                providers: IndexVec<CrateNum, Providers<$tcx>>,
-                fallback_extern_providers: Providers<$tcx>,
-                on_disk_cache: OnDiskCache<'tcx>,
-            ) -> Self {
-                Queries {
-                    providers,
-                    fallback_extern_providers: Box::new(fallback_extern_providers),
-                    on_disk_cache,
-                    $($name: Default::default()),*
-                }
-            }
-
-            pub fn try_collect_active_jobs(
-                &self
-            ) -> Option<FxHashMap<QueryJobId, QueryJobInfo<'tcx>>> {
-                let mut jobs = FxHashMap::default();
-
-                $(
-                    // We use try_lock_shards here since we are called from the
-                    // deadlock handler, and this shouldn't be locked.
-                    let shards = self.$name.shards.try_lock_shards()?;
-                    let shards = shards.iter().enumerate();
-                    jobs.extend(shards.flat_map(|(shard_id, shard)| {
-                        shard.active.iter().filter_map(move |(k, v)| {
-                        if let QueryResult::Started(ref job) = *v {
-                                let id = QueryJobId {
-                                    job: job.id,
-                                    shard:  u16::try_from(shard_id).unwrap(),
-                                    kind:
-                                        <queries::$name<'tcx> as QueryAccessors<'tcx>>::dep_kind(),
-                                };
-                                let info = QueryInfo {
-                                    span: job.span,
-                                    query: queries::$name::query(k.clone())
-                                };
-                                Some((id, QueryJobInfo { info,  job: job.clone() }))
-                        } else {
-                            None
-                        }
-                        })
-                    }));
-                )*
-
-                Some(jobs)
-            }
-        }
-
         #[allow(nonstandard_style)]
         #[derive(Clone, Debug)]
         pub enum Query<$tcx> {
@@ -951,16 +957,6 @@ pub struct $name<$tcx> {
             })*
         }
 
-        // This module and the functions in it exist only to provide a
-        // predictable symbol name prefix for query providers. This is helpful
-        // for analyzing queries in profilers.
-        pub(super) mod __query_compute {
-            $(#[inline(never)]
-            pub fn $name<F: FnOnce() -> R, R>(f: F) -> R {
-                f()
-            })*
-        }
-
         $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> {
             type Key = $K;
             type Value = $V;
@@ -971,16 +967,12 @@ pub fn $name<F: FnOnce() -> R, R>(f: F) -> R {
         impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> {
             const ANON: bool = is_anon!([$($modifiers)*]);
             const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
+            const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$node;
 
             type Cache = query_storage!([$($modifiers)*][$K, $V]);
 
             #[inline(always)]
-            fn query(key: Self::Key) -> Query<'tcx> {
-                Query::$name(key)
-            }
-
-            #[inline(always)]
-            fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<$tcx, Self> {
+            fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<$tcx, Self::Cache> {
                 &tcx.queries.$name
             }
 
@@ -990,23 +982,16 @@ fn to_dep_node(tcx: TyCtxt<$tcx>, key: &Self::Key) -> DepNode {
                 DepConstructor::$node(tcx, *key)
             }
 
-            #[inline(always)]
-            fn dep_kind() -> dep_graph::DepKind {
-                dep_graph::DepKind::$node
-            }
-
             #[inline]
             fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
-                __query_compute::$name(move || {
-                    let provider = tcx.queries.providers.get(key.query_crate())
-                        // HACK(eddyb) it's possible crates may be loaded after
-                        // the query engine is created, and because crate loading
-                        // is not yet integrated with the query engine, such crates
-                        // would be missing appropriate entries in `providers`.
-                        .unwrap_or(&tcx.queries.fallback_extern_providers)
-                        .$name;
-                    provider(tcx, key)
-                })
+                let provider = tcx.queries.providers.get(key.query_crate())
+                    // HACK(eddyb) it's possible crates may be loaded after
+                    // the query engine is created, and because crate loading
+                    // is not yet integrated with the query engine, such crates
+                    // would be missing appropriate entries in `providers`.
+                    .unwrap_or(&tcx.queries.fallback_extern_providers)
+                    .$name;
+                provider(tcx, key)
             }
 
             fn hash_result(
@@ -1139,7 +1124,41 @@ pub struct Queries<$tcx> {
             providers: IndexVec<CrateNum, Providers<$tcx>>,
             fallback_extern_providers: Box<Providers<$tcx>>,
 
-            $($(#[$attr])*  $name: QueryState<$tcx, queries::$name<$tcx>>,)*
+            $($(#[$attr])*  $name: QueryState<
+                $tcx,
+                <queries::$name<$tcx> as QueryAccessors<'tcx>>::Cache,
+            >,)*
+        }
+
+        impl<$tcx> Queries<$tcx> {
+            pub(crate) fn new(
+                providers: IndexVec<CrateNum, Providers<$tcx>>,
+                fallback_extern_providers: Providers<$tcx>,
+                on_disk_cache: OnDiskCache<'tcx>,
+            ) -> Self {
+                Queries {
+                    providers,
+                    fallback_extern_providers: Box::new(fallback_extern_providers),
+                    on_disk_cache,
+                    $($name: Default::default()),*
+                }
+            }
+
+            pub(crate) fn try_collect_active_jobs(
+                &self
+            ) -> Option<FxHashMap<QueryJobId, QueryJobInfo<'tcx>>> {
+                let mut jobs = FxHashMap::default();
+
+                $(
+                    self.$name.try_collect_active_jobs(
+                        <queries::$name<'tcx> as QueryAccessors<'tcx>>::DEP_KIND,
+                        Query::$name,
+                        &mut jobs,
+                    )?;
+                )*
+
+                Some(jobs)
+            }
         }
     };
 }
index 99ada34d59ebed13c5b4829e107e0be83f973c40..58ace917786cf15d70342ddea66c30ee596c65dd 100644 (file)
@@ -1,6 +1,6 @@
 use crate::hir::map::definitions::DefPathData;
 use crate::ty::context::TyCtxt;
-use crate::ty::query::config::QueryAccessors;
+use crate::ty::query::caches::QueryCache;
 use crate::ty::query::plumbing::QueryState;
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
@@ -157,13 +157,14 @@ impl<T0, T1> IntoSelfProfilingString for (T0, T1)
 /// Allocate the self-profiling query strings for a single query cache. This
 /// method is called from `alloc_self_profile_query_strings` which knows all
 /// the queries via macro magic.
-pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, Q>(
+pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
     tcx: TyCtxt<'tcx>,
     query_name: &'static str,
-    query_state: &QueryState<'tcx, Q>,
+    query_state: &QueryState<'tcx, C>,
     string_cache: &mut QueryKeyStringCache,
 ) where
-    Q: QueryAccessors<'tcx>,
+    C: QueryCache,
+    C::Key: Debug + Clone,
 {
     tcx.prof.with_profiler(|profiler| {
         let event_id_builder = profiler.event_id_builder();
index d257320d4eaf652242660491b94603750217d6ed..527bb46c908882ff6d387558b083a267a353a533 100644 (file)
@@ -1,3 +1,4 @@
+use crate::ty::query::caches::QueryCache;
 use crate::ty::query::config::QueryAccessors;
 use crate::ty::query::plumbing::QueryState;
 use crate::ty::query::queries;
@@ -37,20 +38,17 @@ struct QueryStats {
     local_def_id_keys: Option<usize>,
 }
 
-fn stats<'tcx, Q: QueryAccessors<'tcx>>(
-    name: &'static str,
-    map: &QueryState<'tcx, Q>,
-) -> QueryStats {
+fn stats<'tcx, C: QueryCache>(name: &'static str, map: &QueryState<'tcx, C>) -> QueryStats {
     let mut stats = QueryStats {
         name,
         #[cfg(debug_assertions)]
         cache_hits: map.cache_hits.load(Ordering::Relaxed),
         #[cfg(not(debug_assertions))]
         cache_hits: 0,
-        key_size: mem::size_of::<Q::Key>(),
-        key_type: type_name::<Q::Key>(),
-        value_size: mem::size_of::<Q::Value>(),
-        value_type: type_name::<Q::Value>(),
+        key_size: mem::size_of::<C::Key>(),
+        key_type: type_name::<C::Key>(),
+        value_size: mem::size_of::<C::Value>(),
+        value_type: type_name::<C::Value>(),
         entry_count: map.iter_results(|results| results.count()),
         local_def_id_keys: None,
     };
@@ -125,7 +123,9 @@ fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
             let mut queries = Vec::new();
 
             $($(
-                queries.push(stats::<queries::$name<'_>>(
+                queries.push(stats::<
+                    <queries::$name<'_> as QueryAccessors<'_>>::Cache,
+                >(
                     stringify!($name),
                     &tcx.queries.$name,
                 ));
index e3077b9897c18fcd08712eda6f611a2b4d735b76..b7b50617eaaf897839a0ec4950ec8d88576484c5 100644 (file)
@@ -31,7 +31,6 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::thin_vec::ThinVec;
-use rustc_index::vec::Idx;
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{self, Decoder, Encoder};
 use rustc_span::source_map::{respan, Spanned};
@@ -2251,27 +2250,22 @@ pub enum AttrStyle {
     Inner,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, Copy)]
-pub struct AttrId(pub usize);
-
-impl Idx for AttrId {
-    fn new(idx: usize) -> Self {
-        AttrId(idx)
-    }
-    fn index(self) -> usize {
-        self.0
+rustc_index::newtype_index! {
+    pub struct AttrId {
+        ENCODABLE = custom
+        DEBUG_FORMAT = "AttrId({})"
     }
 }
 
 impl rustc_serialize::Encodable for AttrId {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
+    fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
+        Ok(())
     }
 }
 
 impl rustc_serialize::Decodable for AttrId {
-    fn decode<D: Decoder>(d: &mut D) -> Result<AttrId, D::Error> {
-        d.read_nil().map(|_| crate::attr::mk_attr_id())
+    fn decode<D: Decoder>(_: &mut D) -> Result<AttrId, D::Error> {
+        Ok(crate::attr::mk_attr_id())
     }
 }
 
index 249311851fb1bed7d19bebd79b1a9543dad39804..d53d77677859879c904a39e4b429ec6152e73524 100644 (file)
@@ -366,14 +366,14 @@ pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
 }
 
 crate fn mk_attr_id() -> AttrId {
-    use std::sync::atomic::AtomicUsize;
+    use std::sync::atomic::AtomicU32;
     use std::sync::atomic::Ordering;
 
-    static NEXT_ATTR_ID: AtomicUsize = AtomicUsize::new(0);
+    static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0);
 
     let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
-    assert!(id != ::std::usize::MAX);
-    AttrId(id)
+    assert!(id != u32::MAX);
+    AttrId::from_u32(id)
 }
 
 pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
index 541c681840f12cf371e1f8cac325f8b2eb083e8b..b4363778094b4ceedda02d39e2c7f1d77a444f97 100644 (file)
@@ -645,6 +645,8 @@ fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
     }
 }
 
+/// Checks that generic parameters are in the correct order,
+/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
 fn validate_generic_param_order<'a>(
     sess: &Session,
     handler: &rustc_errors::Handler,
index 6d0046063989b57f17a66ed82e4cb8565aab080e..245df0846b583cc8c77ad0140d6b09250a8bbcfb 100644 (file)
@@ -293,7 +293,12 @@ pub fn codegen_rvalue_operand(
                                 if let Some(discr) =
                                     operand.layout.ty.discriminant_for_variant(bx.tcx(), index)
                                 {
-                                    let discr_val = bx.cx().const_uint_big(ll_t_out, discr.val);
+                                    let discr_layout = bx.cx().layout_of(discr.ty);
+                                    let discr_t = bx.cx().immediate_backend_type(discr_layout);
+                                    let discr_val = bx.cx().const_uint_big(discr_t, discr.val);
+                                    let discr_val =
+                                        bx.intcast(discr_val, ll_t_out, discr.ty.is_signed());
+
                                     return (
                                         bx,
                                         OperandRef {
index 85339ab9aa15badd581582ba388c3e2e0200601a..33bfaddc39c9d21eddf958cf2202a92509a43d12 100644 (file)
 E0221: include_str!("./error_codes/E0221.md"),
 E0222: include_str!("./error_codes/E0222.md"),
 E0223: include_str!("./error_codes/E0223.md"),
+E0224: include_str!("./error_codes/E0224.md"),
 E0225: include_str!("./error_codes/E0225.md"),
 E0229: include_str!("./error_codes/E0229.md"),
 E0230: include_str!("./error_codes/E0230.md"),
 //  E0217, // ambiguous associated type, defined in multiple supertraits
 //  E0218, // no associated type defined
 //  E0219, // associated type defined in higher-ranked supertrait
-    E0224, // at least one non-builtin train is required for an object type
     E0226, // only a single explicit lifetime bound is permitted
     E0227, // ambiguous lifetime bound, explicit lifetime bound required
     E0228, // explicit lifetime bound required
diff --git a/src/librustc_error_codes/error_codes/E0224.md b/src/librustc_error_codes/error_codes/E0224.md
new file mode 100644 (file)
index 0000000..fd89c1d
--- /dev/null
@@ -0,0 +1,15 @@
+A trait object was declaired with no traits.
+
+Erroneous code example:
+
+```compile_fail,E0224
+type Foo = dyn 'static +;
+```
+
+Rust does not currently support this.
+
+To solve ensure the the trait object has at least one trait:
+
+```
+type Foo = dyn 'static + Copy;
+```
index 74c304c96b9a45490d82dd6969abdc801c6580da..0fc477bbd0b4c95507287785357dc4b451584d71 100644 (file)
@@ -922,6 +922,7 @@ pub struct ExpansionData {
 pub struct ExtCtxt<'a> {
     pub parse_sess: &'a ParseSess,
     pub ecfg: expand::ExpansionConfig<'a>,
+    pub reduced_recursion_limit: Option<usize>,
     pub root_path: PathBuf,
     pub resolver: &'a mut dyn Resolver,
     pub current_expansion: ExpansionData,
@@ -940,6 +941,7 @@ pub fn new(
         ExtCtxt {
             parse_sess,
             ecfg,
+            reduced_recursion_limit: None,
             resolver,
             extern_mod_loaded,
             root_path: PathBuf::new(),
index b6cc192cc33d6c6b86d64e4816aa8757b12252d3..4f568e5456c725b3bed8d19ef0d1c3f469a71bdb 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
-use rustc_errors::{Applicability, FatalError, PResult};
+use rustc_errors::{Applicability, PResult};
 use rustc_feature::Features;
 use rustc_parse::parser::Parser;
 use rustc_parse::validate_attr;
@@ -645,7 +645,6 @@ fn error_recursion_limit_reached(&mut self) {
             ))
             .emit();
         self.cx.trace_macros_diag();
-        FatalError.raise();
     }
 
     /// A macro's expansion does not fit in this fragment kind.
@@ -665,8 +664,17 @@ fn expand_invoc(
         invoc: Invocation,
         ext: &SyntaxExtensionKind,
     ) -> ExpandResult<AstFragment, Invocation> {
-        if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
-            self.error_recursion_limit_reached();
+        let recursion_limit =
+            self.cx.reduced_recursion_limit.unwrap_or(self.cx.ecfg.recursion_limit);
+        if self.cx.current_expansion.depth > recursion_limit {
+            if self.cx.reduced_recursion_limit.is_none() {
+                self.error_recursion_limit_reached();
+            }
+
+            // Reduce the recursion limit by half each time it triggers.
+            self.cx.reduced_recursion_limit = Some(recursion_limit / 2);
+
+            return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span()));
         }
 
         let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
index ebbfcb28db2f533244821293bf8f538c69f581c6..78f97c40cbd1277f3c9a1af4466b63e3231e755a 100644 (file)
@@ -1784,11 +1784,11 @@ pub fn construct_generic_bound_failure(
         // suggest adding an explicit lifetime bound to it.
         let type_param_span = match (self.in_progress_tables, bound_kind) {
             (Some(ref table), GenericKind::Param(ref param)) => {
-                let table = table.borrow();
-                table.local_id_root.and_then(|did| {
-                    let generics = self.tcx.generics_of(did);
-                    // Account for the case where `did` corresponds to `Self`, which doesn't have
-                    // the expected type argument.
+                let table_owner = table.borrow().hir_owner;
+                table_owner.and_then(|table_owner| {
+                    let generics = self.tcx.generics_of(table_owner.to_def_id());
+                    // Account for the case where `param` corresponds to `Self`,
+                    // which doesn't have the expected type argument.
                     if !(generics.has_self && param.index == 0) {
                         let type_param = generics.type_param(param, self.tcx);
                         let hir = &self.tcx.hir();
index 8bd1514a9fb0a89429efb9cc70c6e69635177312..fbacc31b1178c2e1ecd27350b795a234848f73d1 100644 (file)
@@ -29,7 +29,7 @@
 use rustc_data_structures::unify as ut;
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_session::config::BorrowckMode;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -559,7 +559,7 @@ fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
 impl<'tcx> InferCtxtBuilder<'tcx> {
     /// Used only by `rustc_typeck` during body type-checking/inference,
     /// will initialize `in_progress_tables` with fresh `TypeckTables`.
-    pub fn with_fresh_in_progress_tables(mut self, table_owner: DefId) -> Self {
+    pub fn with_fresh_in_progress_tables(mut self, table_owner: LocalDefId) -> Self {
         self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(Some(table_owner))));
         self
     }
index b7a5f2f4531e59f5129ffdbf8683e9665b066584..8d9e287cdc9d69329166e5a6865fb0e0b26d728b 100644 (file)
@@ -312,6 +312,8 @@ fn configure_and_expand_inner<'a>(
             ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect();
         missing_fragment_specifiers.sort();
 
+        let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
+
         for span in missing_fragment_specifiers {
             let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
             let msg = "missing fragment specifier";
@@ -320,8 +322,15 @@ fn configure_and_expand_inner<'a>(
         if cfg!(windows) {
             env::set_var("PATH", &old_path);
         }
-        krate
-    });
+
+        if recursion_limit_hit {
+            // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
+            // with a large AST
+            Err(ErrorReported)
+        } else {
+            Ok(krate)
+        }
+    })?;
 
     sess.time("maybe_building_test_harness", || {
         rustc_builtin_macros::test_harness::inject(
index 3cbb0667ff3923f051c45ac051c2eb995b5e0254..5c70b28a56786bcc1bf65833ba47bd9f43d641e5 100644 (file)
@@ -3,6 +3,7 @@
 use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
 use rustc_ast::ast::FloatTy;
 use rustc_span::symbol::sym;
+use rustc_target::abi::LayoutOf;
 
 use rustc::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
 use rustc::mir::CastKind;
@@ -134,7 +135,10 @@ fn cast_immediate(
             layout::Variants::Single { index } => {
                 if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
                     assert!(src.layout.is_zst());
-                    return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
+                    let discr_layout = self.layout_of(discr.ty)?;
+                    return Ok(self
+                        .cast_from_int_like(discr.val, discr_layout, dest_layout)?
+                        .into());
                 }
             }
             layout::Variants::Multiple { .. } => {}
@@ -171,10 +175,10 @@ fn cast_immediate(
         // (b) cast from an integer-like (including bool, char, enums).
         // In both cases we want the bits.
         let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
-        Ok(self.cast_from_int(bits, src.layout, dest_layout)?.into())
+        Ok(self.cast_from_int_like(bits, src.layout, dest_layout)?.into())
     }
 
-    fn cast_from_int(
+    fn cast_from_int_like(
         &self,
         v: u128, // raw bits
         src_layout: TyLayout<'tcx>,
index f7fb704fcbc2c13c2a5984c742d32a68235ca98f..6c0b2c40c76221db44b5ff2925d6e9b77069bd6b 100644 (file)
@@ -46,12 +46,20 @@ pub fn new(
         source_file: Lrc<rustc_span::SourceFile>,
         override_span: Option<Span>,
     ) -> Self {
-        if source_file.src.is_none() {
+        // Make sure external source is loaded first, before accessing it.
+        // While this can't show up during normal parsing, `retokenize` may
+        // be called with a source file from an external crate.
+        sess.source_map().ensure_source_file_source_present(source_file.clone());
+
+        // FIXME(eddyb) use `Lrc<str>` or similar to avoid cloning the `String`.
+        let src = if let Some(src) = &source_file.src {
+            src.clone()
+        } else if let Some(src) = source_file.external_src.borrow().get_source() {
+            src.clone()
+        } else {
             sess.span_diagnostic
                 .bug(&format!("cannot lex `source_file` without source: {}", source_file.name));
-        }
-
-        let src = (*source_file.src.as_ref().unwrap()).clone();
+        };
 
         StringReader {
             sess,
index b993857681a301e1456896ababc6ec03df0c17ed..b205a4b322229da9a3c352993047aff7e6e0d7fe 100644 (file)
@@ -925,8 +925,17 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
             self.parse_closure_expr(attrs)
         } else if self.eat_keyword(kw::If) {
             self.parse_if_expr(attrs)
-        } else if self.eat_keyword(kw::For) {
-            self.parse_for_expr(None, self.prev_token.span, attrs)
+        } else if self.check_keyword(kw::For) {
+            if self.choose_generics_over_qpath(1) {
+                // NOTE(Centril, eddyb): DO NOT REMOVE! Beyond providing parser recovery,
+                // this is an insurance policy in case we allow qpaths in (tuple-)struct patterns.
+                // When `for <Foo as Bar>::Proj in $expr $block` is wanted,
+                // you can disambiguate in favor of a pattern with `(...)`.
+                self.recover_quantified_closure_expr(attrs)
+            } else {
+                assert!(self.eat_keyword(kw::For));
+                self.parse_for_expr(None, self.prev_token.span, attrs)
+            }
         } else if self.eat_keyword(kw::While) {
             self.parse_while_expr(None, self.prev_token.span, attrs)
         } else if let Some(label) = self.eat_label() {
@@ -1417,6 +1426,26 @@ pub(super) fn parse_block_expr(
         Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
     }
 
+    /// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`.
+    fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        let lo = self.token.span;
+        let _ = self.parse_late_bound_lifetime_defs()?;
+        let span_for = lo.to(self.prev_token.span);
+        let closure = self.parse_closure_expr(attrs)?;
+
+        self.struct_span_err(span_for, "cannot introduce explicit parameters for a closure")
+            .span_label(closure.span, "the parameters are attached to this closure")
+            .span_suggestion(
+                span_for,
+                "remove the parameters",
+                String::new(),
+                Applicability::MachineApplicable,
+            )
+            .emit();
+
+        Ok(self.mk_expr_err(lo.to(closure.span)))
+    }
+
     /// Parses a closure expression (e.g., `move |args| expr`).
     fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
index 59fd5f7c4be1fc55f414cdb6dce37c985048f1c2..3442c5081c18f879c07ddded71faf7cb3fe6f750 100644 (file)
@@ -181,7 +181,7 @@ pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
         // We are considering adding generics to the `where` keyword as an alternative higher-rank
         // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
         // change we parse those generics now, but report an error.
-        if self.choose_generics_over_qpath() {
+        if self.choose_generics_over_qpath(0) {
             let generics = self.parse_generics()?;
             self.struct_span_err(
                 generics.span,
@@ -257,7 +257,7 @@ fn parse_ty_where_predicate(&mut self) -> PResult<'a, ast::WherePredicate> {
         }
     }
 
-    pub(super) fn choose_generics_over_qpath(&self) -> bool {
+    pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool {
         // There's an ambiguity between generic parameters and qualified paths in impls.
         // If we see `<` it may start both, so we have to inspect some following tokens.
         // The following combinations can only start generics,
@@ -274,15 +274,12 @@ pub(super) fn choose_generics_over_qpath(&self) -> bool {
         // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
         // because this is what almost always expected in practice, qualified paths in impls
         // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
-        self.token == token::Lt
-            && (self.look_ahead(1, |t| t == &token::Pound || t == &token::Gt)
-                || self.look_ahead(1, |t| t.is_lifetime() || t.is_ident())
-                    && self.look_ahead(2, |t| {
-                        t == &token::Gt
-                            || t == &token::Comma
-                            || t == &token::Colon
-                            || t == &token::Eq
+        self.look_ahead(start, |t| t == &token::Lt)
+            && (self.look_ahead(start + 1, |t| t == &token::Pound || t == &token::Gt)
+                || self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident())
+                    && self.look_ahead(start + 2, |t| {
+                        matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
                     })
-                || self.is_keyword_ahead(1, &[kw::Const]))
+                || self.is_keyword_ahead(start + 1, &[kw::Const]))
     }
 }
index 5f37069afbe4c9a2fcd660f621f2e99a95c03306..7a4f76804157f56df3ae750df3b0f6d160777579 100644 (file)
@@ -458,7 +458,7 @@ fn parse_item_impl(
         self.expect_keyword(kw::Impl)?;
 
         // First, parse generic parameters if necessary.
-        let mut generics = if self.choose_generics_over_qpath() {
+        let mut generics = if self.choose_generics_over_qpath(0) {
             self.parse_generics()?
         } else {
             let mut generics = Generics::default();
index 9f6598a0ec1fe6727b54e443067a5a184779278d..9d8b1422bdf2469bc0910ee7bf3ce9d395dd0b69 100644 (file)
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if tcx.features().rustc_attrs {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
-        tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx });
+        tcx.hir().krate().visit_all_item_likes(&mut LayoutTest { tcx });
     }
 }
 
-struct VarianceTest<'tcx> {
+struct LayoutTest<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
 
-impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> {
+impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let item_def_id = self.tcx.hir().local_def_id(item.hir_id);
 
-        if let ItemKind::TyAlias(..) = item.kind {
-            for attr in self.tcx.get_attrs(item_def_id).iter() {
-                if attr.check_name(sym::rustc_layout) {
-                    self.dump_layout_of(item_def_id, item, attr);
+        match item.kind {
+            ItemKind::TyAlias(..)
+            | ItemKind::Enum(..)
+            | ItemKind::Struct(..)
+            | ItemKind::Union(..) => {
+                for attr in self.tcx.get_attrs(item_def_id).iter() {
+                    if attr.check_name(sym::rustc_layout) {
+                        self.dump_layout_of(item_def_id, item, attr);
+                    }
                 }
             }
+            _ => {}
         }
     }
 
@@ -42,7 +48,7 @@ fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
     fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
 }
 
-impl VarianceTest<'tcx> {
+impl LayoutTest<'tcx> {
     fn dump_layout_of(&self, item_def_id: DefId, item: &hir::Item<'tcx>, attr: &Attribute) {
         let tcx = self.tcx;
         let param_env = self.tcx.param_env(item_def_id);
@@ -81,6 +87,13 @@ fn dump_layout_of(&self, item_def_id: DefId, item: &hir::Item<'tcx>, attr: &Attr
                             );
                         }
 
+                        sym::debug => {
+                            self.tcx.sess.span_err(
+                                item.span,
+                                &format!("layout debugging: {:#?}", *ty_layout),
+                            );
+                        }
+
                         name => {
                             self.tcx.sess.span_err(
                                 meta_item.span(),
index dbc180114f1c1dafd90a9f296a057d1023457736..28864737072b291051012d2349b06587c0cd21bf 100644 (file)
@@ -856,7 +856,7 @@ pub enum ExternalSource {
 #[derive(PartialEq, Eq, Clone, Debug)]
 pub enum ExternalSourceKind {
     /// The external source has been loaded already.
-    Present(String),
+    Present(Lrc<String>),
     /// No attempt has been made to load the external source.
     AbsentOk,
     /// A failed attempt has been made to load the external source.
@@ -872,7 +872,7 @@ pub fn is_absent(&self) -> bool {
         }
     }
 
-    pub fn get_source(&self) -> Option<&str> {
+    pub fn get_source(&self) -> Option<&Lrc<String>> {
         match self {
             ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src),
             _ => None,
@@ -1138,7 +1138,7 @@ pub fn add_external_src<F>(&self, get_src: F) -> bool
                     hasher.write(src.as_bytes());
 
                     if hasher.finish::<u128>() == self.src_hash {
-                        *src_kind = ExternalSourceKind::Present(src);
+                        *src_kind = ExternalSourceKind::Present(Lrc::new(src));
                         return true;
                     }
                 } else {
index 35a97cfd3c3c21f98b7e8438f90acf43d550dffb..dcb4e849a75e8f34be5a7d592347117391a76ddf 100644 (file)
         debug_trait,
         declare_lint_pass,
         decl_macro,
+        debug,
         Debug,
         Decodable,
         Default,
index 0dedda9bb6b73e67c0017ab9f063dd494124dd3f..7b082309f34b549343cd01a36a19bc1926381720 100644 (file)
@@ -59,10 +59,14 @@ pub(super) fn mangle(
         .print_def_path(def_id, &[])
         .unwrap();
 
-    if instance.is_vtable_shim() {
+    if let ty::InstanceDef::VtableShim(..) = instance.def {
         let _ = printer.write_str("{{vtable-shim}}");
     }
 
+    if let ty::InstanceDef::ReifyShim(..) = instance.def {
+        let _ = printer.write_str("{{reify-shim}}");
+    }
+
     printer.path.finish(hash)
 }
 
@@ -123,7 +127,8 @@ fn get_symbol_hash<'tcx>(
         }
 
         // We want to avoid accidental collision between different types of instances.
-        // Especially, VtableShim may overlap with its original instance without this.
+        // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
+        // instances without this.
         discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher);
     });
 
index ce6d0d9dc5ba8962782f90079cf2da8161e0bb53..e22a49061bb19efb1dc556ef4e8baf89f5bf9306 100644 (file)
@@ -34,8 +34,17 @@ pub(super) fn mangle(
         binders: vec![],
         out: String::from(prefix),
     };
-    cx = if instance.is_vtable_shim() {
-        cx.path_append_ns(|cx| cx.print_def_path(def_id, substs), 'S', 0, "").unwrap()
+
+    // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance.
+    let shim_kind = match instance.def {
+        ty::InstanceDef::VtableShim(_) => Some("vtable"),
+        ty::InstanceDef::ReifyShim(_) => Some("reify"),
+
+        _ => None,
+    };
+
+    cx = if let Some(shim_kind) = shim_kind {
+        cx.path_append_ns(|cx| cx.print_def_path(def_id, substs), 'S', 0, shim_kind).unwrap()
     } else {
         cx.print_def_path(def_id, substs).unwrap()
     };
index 553dbdca58b25448d949b5a8b5893082061e2e5b..40eb893e6daa85e3d0ef353a27da5d333e1881d7 100644 (file)
@@ -1105,15 +1105,15 @@ fn maybe_note_obligation_cause_for_async_await(
         let generator_did_root = self.tcx.closure_base_def_id(generator_did);
         debug!(
             "maybe_note_obligation_cause_for_async_await: generator_did={:?} \
-             generator_did_root={:?} in_progress_tables.local_id_root={:?} span={:?}",
+             generator_did_root={:?} in_progress_tables.hir_owner={:?} span={:?}",
             generator_did,
             generator_did_root,
-            in_progress_tables.as_ref().map(|t| t.local_id_root),
+            in_progress_tables.as_ref().map(|t| t.hir_owner),
             span
         );
         let query_tables;
         let tables: &TypeckTables<'tcx> = match &in_progress_tables {
-            Some(t) if t.local_id_root == Some(generator_did_root) => t,
+            Some(t) if t.hir_owner.map(|owner| owner.to_def_id()) == Some(generator_did_root) => t,
             _ => {
                 query_tables = self.tcx.typeck_tables_of(generator_did);
                 &query_tables
index a2832d92d4aebdbc62a2843d3bc1420671bd623e..6178158e4e504c7555c256fdcf004a118fd916d0 100644 (file)
@@ -213,7 +213,7 @@ fn compare_predicate_entailment<'tcx>(
     );
 
     tcx.infer_ctxt().enter(|infcx| {
-        let inh = Inherited::new(infcx, impl_m.def_id);
+        let inh = Inherited::new(infcx, impl_m.def_id.expect_local());
         let infcx = &inh.infcx;
 
         debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds);
@@ -950,7 +950,7 @@ fn nested_visit_map(
 
     tcx.infer_ctxt().enter(|infcx| {
         let param_env = tcx.param_env(impl_c.def_id);
-        let inh = Inherited::new(infcx, impl_c.def_id);
+        let inh = Inherited::new(infcx, impl_c.def_id.expect_local());
         let infcx = &inh.infcx;
 
         // The below is for the most part highly similar to the procedure
@@ -1130,7 +1130,7 @@ fn compare_type_predicate_entailment(
         normalize_cause.clone(),
     );
     tcx.infer_ctxt().enter(|infcx| {
-        let inh = Inherited::new(infcx, impl_ty.def_id);
+        let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
         let infcx = &inh.infcx;
 
         debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds);
index 2f0eb5e06709a0191fc4ebb04d8686684172f168..061433bcf6515749cc7305a2e66dddc98de03012 100644 (file)
@@ -1018,9 +1018,9 @@ fn suggest_traits_to_import<'b>(
             // Obtain the span for `param` and use it for a structured suggestion.
             let mut suggested = false;
             if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
-                let table = table.borrow();
-                if let Some(did) = table.local_id_root {
-                    let generics = self.tcx.generics_of(did);
+                let table_owner = table.borrow().hir_owner;
+                if let Some(table_owner) = table_owner {
+                    let generics = self.tcx.generics_of(table_owner.to_def_id());
                     let type_param = generics.type_param(param, self.tcx);
                     let hir = &self.tcx.hir();
                     if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
index 94bbd3701d81e6158b901f823ae0c46a8a945b57..e4bd42f61c32129bd5c385fe5676979f02afbe0f 100644 (file)
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
@@ -633,19 +633,15 @@ fn deref(&self) -> &Self::Target {
 /// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`.
 pub struct InheritedBuilder<'tcx> {
     infcx: infer::InferCtxtBuilder<'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
 }
 
 impl Inherited<'_, 'tcx> {
-    pub fn build(tcx: TyCtxt<'tcx>, def_id: DefId) -> InheritedBuilder<'tcx> {
-        let hir_id_root = if let Some(def_id) = def_id.as_local() {
-            tcx.hir().local_def_id_to_hir_id(def_id).owner.to_def_id()
-        } else {
-            def_id
-        };
+    pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
+        let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
 
         InheritedBuilder {
-            infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(hir_id_root),
+            infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(hir_owner),
             def_id,
         }
     }
@@ -662,10 +658,10 @@ fn enter<F, R>(&mut self, f: F) -> R
 }
 
 impl Inherited<'a, 'tcx> {
-    fn new(infcx: InferCtxt<'a, 'tcx>, def_id: DefId) -> Self {
+    fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
         let tcx = infcx.tcx;
-        let item_id = tcx.hir().as_local_hir_id(def_id);
-        let body_id = item_id.and_then(|id| tcx.hir().maybe_body_owned_by(id));
+        let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        let body_id = tcx.hir().maybe_body_owned_by(item_id);
         let implicit_region_bound = body_id.map(|body_id| {
             let body = tcx.hir().body(body_id);
             tcx.mk_region(ty::ReScope(region::Scope {
@@ -1002,7 +998,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
     });
     let body = tcx.hir().body(body_id);
 
-    let tables = Inherited::build(tcx, def_id).enter(|inh| {
+    let tables = Inherited::build(tcx, def_id.expect_local()).enter(|inh| {
         let param_env = tcx.param_env(def_id);
         let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) {
             let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
@@ -1127,7 +1123,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
 
     // Consistency check our TypeckTables instance can hold all ItemLocalIds
     // it will need to hold.
-    assert_eq!(tables.local_id_root, Some(id.owner.to_def_id()));
+    assert_eq!(tables.hir_owner, Some(id.owner));
 
     tables
 }
index 3255d7b435c8fb55ce387c055494107c45613e29..72c58af7912fba51ac76e0ecb849e6f45b9367c1 100644 (file)
@@ -316,12 +316,12 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<
 }
 
 fn for_id(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) -> CheckWfFcxBuilder<'_> {
-    let def_id = tcx.hir().local_def_id(id);
+    let def_id = tcx.hir().local_def_id(id).expect_local();
     CheckWfFcxBuilder {
         inherited: Inherited::build(tcx, def_id),
         id,
         span,
-        param_env: tcx.param_env(def_id),
+        param_env: tcx.param_env(def_id.to_def_id()),
     }
 }
 
index fd92284effb322842c8af3ffb8309889fd6fc2de..65f81ef033dd7288300b46928bb809c83d1569a8 100644 (file)
@@ -111,7 +111,7 @@ fn new(
 
         WritebackCx {
             fcx,
-            tables: ty::TypeckTables::empty(Some(owner.to_def_id())),
+            tables: ty::TypeckTables::empty(Some(owner)),
             body,
             rustc_dump_user_substs,
         }
@@ -338,11 +338,11 @@ fn visit_upvar_capture_map(&mut self) {
 
     fn visit_closures(&mut self) {
         let fcx_tables = self.fcx.tables.borrow();
-        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
-        let common_local_id_root = fcx_tables.local_id_root.unwrap();
+        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
+        let common_hir_owner = fcx_tables.hir_owner.unwrap();
 
         for (&id, &origin) in fcx_tables.closure_kind_origins().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id: id };
+            let hir_id = hir::HirId { owner: common_hir_owner, local_id: id };
             self.tables.closure_kind_origins_mut().insert(hir_id, origin);
         }
     }
@@ -350,7 +350,7 @@ fn visit_closures(&mut self) {
     fn visit_coercion_casts(&mut self) {
         let fcx_tables = self.fcx.tables.borrow();
         let fcx_coercion_casts = fcx_tables.coercion_casts();
-        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
+        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
 
         for local_id in fcx_coercion_casts {
             self.tables.set_coercion_cast(*local_id);
@@ -359,12 +359,12 @@ fn visit_coercion_casts(&mut self) {
 
     fn visit_user_provided_tys(&mut self) {
         let fcx_tables = self.fcx.tables.borrow();
-        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
-        let common_local_id_root = fcx_tables.local_id_root.unwrap();
+        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
+        let common_hir_owner = fcx_tables.hir_owner.unwrap();
 
         let mut errors_buffer = Vec::new();
         for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id };
+            let hir_id = hir::HirId { owner: common_hir_owner, local_id };
 
             if cfg!(debug_assertions) && c_ty.has_local_value() {
                 span_bug!(hir_id.to_span(self.fcx.tcx), "writeback: `{:?}` is a local value", c_ty);
@@ -397,7 +397,7 @@ fn visit_user_provided_tys(&mut self) {
 
     fn visit_user_provided_sigs(&mut self) {
         let fcx_tables = self.fcx.tables.borrow();
-        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
+        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
 
         for (&def_id, c_sig) in fcx_tables.user_provided_sigs.iter() {
             if cfg!(debug_assertions) && c_sig.has_local_value() {
@@ -414,7 +414,7 @@ fn visit_user_provided_sigs(&mut self) {
 
     fn visit_generator_interior_types(&mut self) {
         let fcx_tables = self.fcx.tables.borrow();
-        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
+        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
         self.tables.generator_interior_types = fcx_tables.generator_interior_types.clone();
     }
 
@@ -553,11 +553,11 @@ fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
 
     fn visit_liberated_fn_sigs(&mut self) {
         let fcx_tables = self.fcx.tables.borrow();
-        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
-        let common_local_id_root = fcx_tables.local_id_root.unwrap();
+        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
+        let common_hir_owner = fcx_tables.hir_owner.unwrap();
 
         for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id };
+            let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let fn_sig = self.resolve(fn_sig, &hir_id);
             self.tables.liberated_fn_sigs_mut().insert(hir_id, fn_sig.clone());
         }
@@ -565,11 +565,11 @@ fn visit_liberated_fn_sigs(&mut self) {
 
     fn visit_fru_field_types(&mut self) {
         let fcx_tables = self.fcx.tables.borrow();
-        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
-        let common_local_id_root = fcx_tables.local_id_root.unwrap();
+        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
+        let common_hir_owner = fcx_tables.hir_owner.unwrap();
 
         for (&local_id, ftys) in fcx_tables.fru_field_types().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id };
+            let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let ftys = self.resolve(ftys, &hir_id);
             self.tables.fru_field_types_mut().insert(hir_id, ftys);
         }
index 9fbff0399429d5385d9f4be73685e8c892baaeb4..a79c065307796e9f719fd21a8129fa4917cded4b 100644 (file)
@@ -1306,47 +1306,67 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
     // Now create the real type and const parameters.
     let type_start = own_start - has_self as u32 + params.len() as u32;
     let mut i = 0;
-    params.extend(ast_generics.params.iter().filter_map(|param| {
-        let kind = match param.kind {
-            GenericParamKind::Type { ref default, synthetic, .. } => {
-                if !allow_defaults && default.is_some() {
-                    if !tcx.features().default_type_parameter_fallback {
-                        tcx.struct_span_lint_hir(
-                            lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                            param.hir_id,
-                            param.span,
-                            |lint| {
-                                lint.build(
-                                    "defaults for type parameters are only allowed in \
-                                            `struct`, `enum`, `type`, or `trait` definitions.",
-                                )
-                                .emit();
-                            },
-                        );
-                    }
-                }
 
-                ty::GenericParamDefKind::Type {
-                    has_default: default.is_some(),
-                    object_lifetime_default: object_lifetime_defaults
-                        .as_ref()
-                        .map_or(rl::Set1::Empty, |o| o[i]),
-                    synthetic,
+    // FIXME(const_generics): a few places in the compiler expect generic params
+    // to be in the order lifetimes, then type params, then const params.
+    //
+    // To prevent internal errors in case const parameters are supplied before
+    // type parameters we first add all type params, then all const params.
+    params.extend(ast_generics.params.iter().filter_map(|param| {
+        if let GenericParamKind::Type { ref default, synthetic, .. } = param.kind {
+            if !allow_defaults && default.is_some() {
+                if !tcx.features().default_type_parameter_fallback {
+                    tcx.struct_span_lint_hir(
+                        lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                        param.hir_id,
+                        param.span,
+                        |lint| {
+                            lint.build(
+                                "defaults for type parameters are only allowed in \
+                                        `struct`, `enum`, `type`, or `trait` definitions.",
+                            )
+                            .emit();
+                        },
+                    );
                 }
             }
-            GenericParamKind::Const { .. } => ty::GenericParamDefKind::Const,
-            _ => return None,
-        };
 
-        let param_def = ty::GenericParamDef {
-            index: type_start + i as u32,
-            name: param.name.ident().name,
-            def_id: tcx.hir().local_def_id(param.hir_id),
-            pure_wrt_drop: param.pure_wrt_drop,
-            kind,
-        };
-        i += 1;
-        Some(param_def)
+            let kind = ty::GenericParamDefKind::Type {
+                has_default: default.is_some(),
+                object_lifetime_default: object_lifetime_defaults
+                    .as_ref()
+                    .map_or(rl::Set1::Empty, |o| o[i]),
+                synthetic,
+            };
+
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                name: param.name.ident().name,
+                def_id: tcx.hir().local_def_id(param.hir_id),
+                pure_wrt_drop: param.pure_wrt_drop,
+                kind,
+            };
+            i += 1;
+            Some(param_def)
+        } else {
+            None
+        }
+    }));
+
+    params.extend(ast_generics.params.iter().filter_map(|param| {
+        if let GenericParamKind::Const { .. } = param.kind {
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                name: param.name.ident().name,
+                def_id: tcx.hir().local_def_id(param.hir_id),
+                pure_wrt_drop: param.pure_wrt_drop,
+                kind: ty::GenericParamDefKind::Const,
+            };
+            i += 1;
+            Some(param_def)
+        } else {
+            None
+        }
     }));
 
     // provide junk type parameter defs - the only place that
index 44ef4ebd463d7448671438ccd5cd87d9d940ac0c..55642dfb4557b3f6c073180f0030809f86080861 100644 (file)
@@ -256,15 +256,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         // figure out which generic parameter it corresponds to and return
                         // the relevant type.
                         let generics = match path.res {
-                            Res::Def(DefKind::Ctor(..), def_id) => {
+                            Res::Def(DefKind::Ctor(..), def_id)
+                            | Res::Def(DefKind::AssocTy, def_id) => {
                                 tcx.generics_of(tcx.parent(def_id).unwrap())
                             }
                             Res::Def(_, def_id) => tcx.generics_of(def_id),
-                            Res::Err => return tcx.types.err,
                             res => {
                                 tcx.sess.delay_span_bug(
                                     DUMMY_SP,
-                                    &format!("unexpected const parent path def {:?}", res,),
+                                    &format!(
+                                        "unexpected const parent path def, parent: {:?}, def: {:?}",
+                                        parent_node, res
+                                    ),
                                 );
                                 return tcx.types.err;
                             }
@@ -284,7 +287,16 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                             .map(|param| tcx.type_of(param.def_id))
                             // This is no generic parameter associated with the arg. This is
                             // probably from an extra arg where one is not needed.
-                            .unwrap_or(tcx.types.err)
+                            .unwrap_or_else(|| {
+                                tcx.sess.delay_span_bug(
+                                    DUMMY_SP,
+                                    &format!(
+                                        "missing generic parameter for `AnonConst`, parent {:?}",
+                                        parent_node
+                                    ),
+                                );
+                                tcx.types.err
+                            })
                     } else {
                         tcx.sess.delay_span_bug(
                             DUMMY_SP,
index 2a370f192964f8b5ae0841abfc6006128024abe8..b394f2efc2e35cfa5ee1b309f035b3dec343368c 100644 (file)
@@ -88,7 +88,7 @@ pub trait Error: Debug + Display {
     /// fn main() {
     ///     match get_super_error() {
     ///         Err(e) => {
-    ///             println!("Error: {}", e.description());
+    ///             println!("Error: {}", e);
     ///             println!("Caused by: {}", e.source().unwrap());
     ///         }
     ///         _ => println!("No error"),
index dc831432c176f22d861f30fd8b1d5871071239f2..83c492fecf9745d0c936d339b73b3b93ee3df62c 100644 (file)
@@ -502,7 +502,7 @@ pub trait Read {
     /// how many bytes were read.
     ///
     /// This function does not provide any guarantees about whether it blocks
-    /// waiting for data, but if an object needs to block for a read but cannot
+    /// waiting for data, but if an object needs to block for a read and cannot,
     /// it will typically signal this via an [`Err`] return value.
     ///
     /// If the return value of this method is [`Ok(n)`], then it must be
index 0fb0757792ed7c3ade51ac38223d597db3aed1ee..9a82ae7626d9714094ac733402e8950284d5e983 100644 (file)
@@ -6,7 +6,7 @@
 use crate::fmt;
 use crate::io::lazy::Lazy;
 use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
-use crate::sync::{Arc, Mutex, MutexGuard};
+use crate::sync::{Arc, Mutex, MutexGuard, Once};
 use crate::sys::stdio;
 use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
 use crate::thread::LocalKey;
@@ -493,7 +493,11 @@ fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
             Ok(stdout) => Maybe::Real(stdout),
             _ => Maybe::Fake,
         };
-        Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))))
+        unsafe {
+            let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))));
+            ret.init();
+            return ret;
+        }
     }
 }
 
@@ -520,7 +524,7 @@ impl Stdout {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn lock(&self) -> StdoutLock<'_> {
-        StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
+        StdoutLock { inner: self.inner.lock() }
     }
 }
 
@@ -581,7 +585,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// an error.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Stderr {
-    inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>,
+    inner: &'static ReentrantMutex<RefCell<Maybe<StderrRaw>>>,
 }
 
 /// A locked reference to the `Stderr` handle.
@@ -639,19 +643,28 @@ pub struct StderrLock<'a> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stderr() -> Stderr {
-    static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new();
-    return Stderr {
-        inner: unsafe { INSTANCE.get(stderr_init).expect("cannot access stderr during shutdown") },
-    };
-
-    fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
-        // This must not reentrantly access `INSTANCE`
-        let stderr = match stderr_raw() {
-            Ok(stderr) => Maybe::Real(stderr),
-            _ => Maybe::Fake,
-        };
-        Arc::new(ReentrantMutex::new(RefCell::new(stderr)))
-    }
+    // Note that unlike `stdout()` we don't use `Lazy` here which registers a
+    // destructor. Stderr is not buffered nor does the `stderr_raw` type consume
+    // any owned resources, so there's no need to run any destructors at some
+    // point in the future.
+    //
+    // This has the added benefit of allowing `stderr` to be usable during
+    // process shutdown as well!
+    static INSTANCE: ReentrantMutex<RefCell<Maybe<StderrRaw>>> =
+        unsafe { ReentrantMutex::new(RefCell::new(Maybe::Fake)) };
+
+    // When accessing stderr we need one-time initialization of the reentrant
+    // mutex, followed by one-time detection of whether we actually have a
+    // stderr handle or not. Afterwards we can just always use the now-filled-in
+    // `INSTANCE` value.
+    static INIT: Once = Once::new();
+    INIT.call_once(|| unsafe {
+        INSTANCE.init();
+        if let Ok(stderr) = stderr_raw() {
+            *INSTANCE.lock().borrow_mut() = Maybe::Real(stderr);
+        }
+    });
+    return Stderr { inner: &INSTANCE };
 }
 
 impl Stderr {
@@ -677,7 +690,7 @@ impl Stderr {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn lock(&self) -> StderrLock<'_> {
-        StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
+        StderrLock { inner: self.inner.lock() }
     }
 }
 
index 57cba6b1f7a1be6949bb0d85dd8d5a15e43f2d57..de6360cf020f5740cd3a31a5ff80a5d6748be1da 100644 (file)
@@ -989,11 +989,26 @@ fn to_socket_addr_string() {
         // s has been moved into the tsa call
     }
 
-    // FIXME: figure out why this fails on openbsd and fix it
     #[test]
-    #[cfg(not(any(windows, target_os = "openbsd")))]
-    fn to_socket_addr_str_bad() {
-        assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err());
+    fn bind_udp_socket_bad() {
+        // rust-lang/rust#53957: This is a regression test for a parsing problem
+        // discovered as part of issue rust-lang/rust#23076, where we were
+        // incorrectly parsing invalid input and then that would result in a
+        // successful `UdpSocket` binding when we would expect failure.
+        //
+        // At one time, this test was written as a call to `tsa` with
+        // INPUT_23076. However, that structure yields an unreliable test,
+        // because it ends up passing junk input to the DNS server, and some DNS
+        // servers will respond with `Ok` to such input, with the ip address of
+        // the DNS server itself.
+        //
+        // This form of the test is more robust: even when the DNS server
+        // returns its own address, it is still an error to bind a UDP socket to
+        // a non-local address, and so we still get an error here in that case.
+
+        const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300";
+
+        assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err())
     }
 
     #[test]
index 4aa25e2505271b0c5dff3468be80e31cf70ff5d3..580ab0e8ad863face1a94e6243a19d72a21960fe 100644 (file)
@@ -53,16 +53,16 @@ pub struct ReentrantMutex {
 }
 
 impl ReentrantMutex {
-    pub unsafe fn uninitialized() -> ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
         ReentrantMutex {
             lock: UnsafeCell::new(MaybeUninit::uninit()),
             recursion: UnsafeCell::new(MaybeUninit::uninit()),
         }
     }
 
-    pub unsafe fn init(&mut self) {
-        self.lock = UnsafeCell::new(MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)));
-        self.recursion = UnsafeCell::new(MaybeUninit::new(0));
+    pub unsafe fn init(&self) {
+        *self.lock.get() = MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0));
+        *self.recursion.get() = MaybeUninit::new(0);
     }
 
     pub unsafe fn try_lock(&self) -> bool {
index b5c75f738d228e170f0d07d21a7a7e0e24d353c1..3d4813209cbc4d0030dca9030f28afe18e6a83e7 100644 (file)
@@ -46,13 +46,13 @@ pub struct ReentrantMutex {
 }
 
 impl ReentrantMutex {
-    pub unsafe fn uninitialized() -> ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
         ReentrantMutex { inner: ptr::null() }
     }
 
     #[inline]
-    pub unsafe fn init(&mut self) {
-        let _ = abi::recmutex_init(&mut self.inner as *mut *const c_void);
+    pub unsafe fn init(&self) {
+        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
     }
 
     #[inline]
index eebbea1b285bab690e6a790a7e1a44c7f95f9945..4911c2f5387690877a75b1e8b4d372d6cc51854f 100644 (file)
@@ -75,7 +75,7 @@ pub const fn uninitialized() -> ReentrantMutex {
     }
 
     #[inline]
-    pub unsafe fn init(&mut self) {}
+    pub unsafe fn init(&self) {}
 
     #[inline]
     pub unsafe fn lock(&self) {
index b38375a2e03c5cd4a2d016d82cfa4cdd12fee1a9..103d87e3d2f91c075fbe8437d1496bc8620bd3db 100644 (file)
@@ -92,11 +92,11 @@ unsafe impl Send for ReentrantMutex {}
 unsafe impl Sync for ReentrantMutex {}
 
 impl ReentrantMutex {
-    pub unsafe fn uninitialized() -> ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
         ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
     }
 
-    pub unsafe fn init(&mut self) {
+    pub unsafe fn init(&self) {
         let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
         let result = libc::pthread_mutexattr_init(attr.as_mut_ptr());
         debug_assert_eq!(result, 0);
index b38375a2e03c5cd4a2d016d82cfa4cdd12fee1a9..103d87e3d2f91c075fbe8437d1496bc8620bd3db 100644 (file)
@@ -92,11 +92,11 @@ unsafe impl Send for ReentrantMutex {}
 unsafe impl Sync for ReentrantMutex {}
 
 impl ReentrantMutex {
-    pub unsafe fn uninitialized() -> ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
         ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
     }
 
-    pub unsafe fn init(&mut self) {
+    pub unsafe fn init(&self) {
         let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
         let result = libc::pthread_mutexattr_init(attr.as_mut_ptr());
         debug_assert_eq!(result, 0);
index 07238d087308fe512e7ae4a38f05b43c73500f9b..7aaf1b3a343b613637c3cb443087c8928356cc16 100644 (file)
@@ -47,11 +47,11 @@ pub unsafe fn destroy(&self) {}
 pub struct ReentrantMutex {}
 
 impl ReentrantMutex {
-    pub unsafe fn uninitialized() -> ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
         ReentrantMutex {}
     }
 
-    pub unsafe fn init(&mut self) {}
+    pub unsafe fn init(&self) {}
 
     pub unsafe fn lock(&self) {}
 
index 90c628a19c22e940c42658d70d041557c2625c8b..268a53bb5641ca58ca79b89b75310b6d3d5c91d8 100644 (file)
@@ -80,11 +80,11 @@ unsafe impl Sync for ReentrantMutex {}
 // released when this recursion counter reaches 0.
 
 impl ReentrantMutex {
-    pub unsafe fn uninitialized() -> ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
         ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
     }
 
-    pub unsafe fn init(&mut self) {
+    pub unsafe fn init(&self) {
         // nothing to do...
     }
 
index 281eb294c65d85da41bfaf35c58e2372c3fce96e..63dfc640908e94da6e82418dd0368fd0df43b9e7 100644 (file)
@@ -109,7 +109,7 @@ unsafe fn remutex(&self) -> *mut ReentrantMutex {
             0 => {}
             n => return n as *mut _,
         }
-        let mut re = box ReentrantMutex::uninitialized();
+        let re = box ReentrantMutex::uninitialized();
         re.init();
         let re = Box::into_raw(re);
         match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) {
@@ -157,11 +157,11 @@ unsafe impl Send for ReentrantMutex {}
 unsafe impl Sync for ReentrantMutex {}
 
 impl ReentrantMutex {
-    pub fn uninitialized() -> ReentrantMutex {
+    pub const fn uninitialized() -> ReentrantMutex {
         ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) }
     }
 
-    pub unsafe fn init(&mut self) {
+    pub unsafe fn init(&self) {
         c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr());
     }
 
index a1ad44a3666edc7e961283050fadc6bbe6864056..4f19bbc467f33d19b47d70a7fc320562d58506f5 100644 (file)
@@ -3,7 +3,6 @@
 use crate::ops::Deref;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::sys::mutex as sys;
-use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
 
 /// A re-entrant mutual exclusion
 ///
@@ -11,8 +10,7 @@
 /// available. The thread which has already locked the mutex can lock it
 /// multiple times without blocking, preventing a common source of deadlocks.
 pub struct ReentrantMutex<T> {
-    inner: Box<sys::ReentrantMutex>,
-    poison: poison::Flag,
+    inner: sys::ReentrantMutex,
     data: T,
 }
 
@@ -39,23 +37,30 @@ pub struct ReentrantMutexGuard<'a, T: 'a> {
     // funny underscores due to how Deref currently works (it disregards field
     // privacy).
     __lock: &'a ReentrantMutex<T>,
-    __poison: poison::Guard,
 }
 
 impl<T> !marker::Send for ReentrantMutexGuard<'_, T> {}
 
 impl<T> ReentrantMutex<T> {
     /// Creates a new reentrant mutex in an unlocked state.
-    pub fn new(t: T) -> ReentrantMutex<T> {
-        unsafe {
-            let mut mutex = ReentrantMutex {
-                inner: box sys::ReentrantMutex::uninitialized(),
-                poison: poison::Flag::new(),
-                data: t,
-            };
-            mutex.inner.init();
-            mutex
-        }
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe because it is required that `init` is called
+    /// once this mutex is in its final resting place, and only then are the
+    /// lock/unlock methods safe.
+    pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
+        ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
+    }
+
+    /// Initializes this mutex so it's ready for use.
+    ///
+    /// # Unsafety
+    ///
+    /// Unsafe to call more than once, and must be called after this will no
+    /// longer move in memory.
+    pub unsafe fn init(&self) {
+        self.inner.init();
     }
 
     /// Acquires a mutex, blocking the current thread until it is able to do so.
@@ -70,7 +75,7 @@ pub fn new(t: T) -> ReentrantMutex<T> {
     /// If another user of this mutex panicked while holding the mutex, then
     /// this call will return failure if the mutex would otherwise be
     /// acquired.
-    pub fn lock(&self) -> LockResult<ReentrantMutexGuard<'_, T>> {
+    pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
         unsafe { self.inner.lock() }
         ReentrantMutexGuard::new(&self)
     }
@@ -87,12 +92,8 @@ pub fn lock(&self) -> LockResult<ReentrantMutexGuard<'_, T>> {
     /// If another user of this mutex panicked while holding the mutex, then
     /// this call will return failure if the mutex would otherwise be
     /// acquired.
-    pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<'_, T>> {
-        if unsafe { self.inner.try_lock() } {
-            Ok(ReentrantMutexGuard::new(&self)?)
-        } else {
-            Err(TryLockError::WouldBlock)
-        }
+    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
+        if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None }
     }
 }
 
@@ -108,11 +109,8 @@ fn drop(&mut self) {
 impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.try_lock() {
-            Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
-            Err(TryLockError::Poisoned(err)) => {
-                f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish()
-            }
-            Err(TryLockError::WouldBlock) => {
+            Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
+            None => {
                 struct LockedPlaceholder;
                 impl fmt::Debug for LockedPlaceholder {
                     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -127,11 +125,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
-    fn new(lock: &'mutex ReentrantMutex<T>) -> LockResult<ReentrantMutexGuard<'mutex, T>> {
-        poison::map_result(lock.poison.borrow(), |guard| ReentrantMutexGuard {
-            __lock: lock,
-            __poison: guard,
-        })
+    fn new(lock: &'mutex ReentrantMutex<T>) -> ReentrantMutexGuard<'mutex, T> {
+        ReentrantMutexGuard { __lock: lock }
     }
 }
 
@@ -147,7 +142,6 @@ impl<T> Drop for ReentrantMutexGuard<'_, T> {
     #[inline]
     fn drop(&mut self) {
         unsafe {
-            self.__lock.poison.done(&self.__poison);
             self.__lock.inner.unlock();
         }
     }
@@ -162,13 +156,17 @@ mod tests {
 
     #[test]
     fn smoke() {
-        let m = ReentrantMutex::new(());
+        let m = unsafe {
+            let m = ReentrantMutex::new(());
+            m.init();
+            m
+        };
         {
-            let a = m.lock().unwrap();
+            let a = m.lock();
             {
-                let b = m.lock().unwrap();
+                let b = m.lock();
                 {
-                    let c = m.lock().unwrap();
+                    let c = m.lock();
                     assert_eq!(*c, ());
                 }
                 assert_eq!(*b, ());
@@ -179,15 +177,19 @@ fn smoke() {
 
     #[test]
     fn is_mutex() {
-        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+        let m = unsafe {
+            let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+            m.init();
+            m
+        };
         let m2 = m.clone();
-        let lock = m.lock().unwrap();
+        let lock = m.lock();
         let child = thread::spawn(move || {
-            let lock = m2.lock().unwrap();
+            let lock = m2.lock();
             assert_eq!(*lock.borrow(), 4950);
         });
         for i in 0..100 {
-            let lock = m.lock().unwrap();
+            let lock = m.lock();
             *lock.borrow_mut() += i;
         }
         drop(lock);
@@ -196,17 +198,21 @@ fn is_mutex() {
 
     #[test]
     fn trylock_works() {
-        let m = Arc::new(ReentrantMutex::new(()));
+        let m = unsafe {
+            let m = Arc::new(ReentrantMutex::new(()));
+            m.init();
+            m
+        };
         let m2 = m.clone();
-        let _lock = m.try_lock().unwrap();
-        let _lock2 = m.try_lock().unwrap();
+        let _lock = m.try_lock();
+        let _lock2 = m.try_lock();
         thread::spawn(move || {
             let lock = m2.try_lock();
-            assert!(lock.is_err());
+            assert!(lock.is_none());
         })
         .join()
         .unwrap();
-        let _lock3 = m.try_lock().unwrap();
+        let _lock3 = m.try_lock();
     }
 
     pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
@@ -215,22 +221,4 @@ fn drop(&mut self) {
             *self.0.borrow_mut() = 42;
         }
     }
-
-    #[test]
-    fn poison_works() {
-        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
-        let mc = m.clone();
-        let result = thread::spawn(move || {
-            let lock = mc.lock().unwrap();
-            *lock.borrow_mut() = 1;
-            let lock2 = mc.lock().unwrap();
-            *lock.borrow_mut() = 2;
-            let _answer = Answer(lock2);
-            panic!("What the answer to my lifetimes dilemma is?");
-        })
-        .join();
-        assert!(result.is_err());
-        let r = m.lock().err().unwrap().into_inner();
-        assert_eq!(*r.borrow(), 42);
-    }
 }
index 3d2d88a676d0d911d196da7695d57fcef72097d8..1da2042b2224ac5e3d93185ed5dd9c01c70123cf 100644 (file)
 // gdb-command: print empty_btree_map
 // gdb-check:$4 = BTreeMap<i32, u32>(len: 0)
 
+// gdb-command: print nasty_btree_map
+// gdb-check:$5 = BTreeMap<i32, pretty_std_collections::MyLeafNode>(len: 1) = {[1] = pretty_std_collections::MyLeafNode (11)}
+
 // gdb-command: print vec_deque
-// gdb-check:$5 = VecDeque<i32>(len: 3, cap: 8) = {5, 3, 7}
+// gdb-check:$6 = VecDeque<i32>(len: 3, cap: 8) = {5, 3, 7}
 
 // gdb-command: print vec_deque2
-// gdb-check:$6 = VecDeque<i32>(len: 7, cap: 8) = {2, 3, 4, 5, 6, 7, 8}
+// gdb-check:$7 = VecDeque<i32>(len: 7, cap: 8) = {2, 3, 4, 5, 6, 7, 8}
 
 #![allow(unused_variables)]
 use std::collections::BTreeMap;
 use std::collections::BTreeSet;
 use std::collections::VecDeque;
 
+struct MyLeafNode(i32); // helps to ensure we don't blindly replace substring "LeafNode"
+
 fn main() {
     // BTreeSet
     let mut btree_set = BTreeSet::new();
@@ -54,6 +59,9 @@ fn main() {
 
     let mut empty_btree_map: BTreeMap<i32, u32> = BTreeMap::new();
 
+    let mut nasty_btree_map: BTreeMap<i32, MyLeafNode> = BTreeMap::new();
+    nasty_btree_map.insert(1, MyLeafNode(11));
+
     // VecDeque
     let mut vec_deque = VecDeque::new();
     vec_deque.push_back(5);
diff --git a/src/test/ui/const-generics/argument_order.rs b/src/test/ui/const-generics/argument_order.rs
new file mode 100644 (file)
index 0000000..3446600
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct Bad<const N: usize, T> { //~ ERROR type parameters must be declared prior
+    arr: [u8; { N }],
+    another: T,
+}
+
+fn main() { }
diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr
new file mode 100644 (file)
index 0000000..1e3b364
--- /dev/null
@@ -0,0 +1,16 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/argument_order.rs:4:28
+   |
+LL | struct Bad<const N: usize, T> {
+   |           -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
+
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/argument_order.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-66906.rs b/src/test/ui/const-generics/issues/issue-66906.rs
new file mode 100644 (file)
index 0000000..461fe83
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+pub struct Tuple;
+
+pub trait Trait<const I: usize> {
+    type Input: From<<Self as Trait<I>>::Input>;
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-66906.stderr b/src/test/ui/const-generics/issues/issue-66906.stderr
new file mode 100644 (file)
index 0000000..f8710b6
--- /dev/null
@@ -0,0 +1,8 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/issue-66906.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/const-generics/issues/issue-70167.rs b/src/test/ui/const-generics/issues/issue-70167.rs
new file mode 100644 (file)
index 0000000..58fac8e
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+pub trait Trait<const N: usize>: From<<Self as Trait<N>>::Item> {
+  type Item;
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-70167.stderr b/src/test/ui/const-generics/issues/issue-70167.stderr
new file mode 100644 (file)
index 0000000..4ba3c20
--- /dev/null
@@ -0,0 +1,8 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/issue-70167.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/consts/cast-discriminant-zst-enum.rs b/src/test/ui/consts/cast-discriminant-zst-enum.rs
new file mode 100644 (file)
index 0000000..a772581
--- /dev/null
@@ -0,0 +1,47 @@
+// run-pass
+// Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to a i32.
+
+#[derive(Copy, Clone)]
+enum Nums {
+    NegOne = -1,
+}
+
+const NEG_ONE_I8: i8 = Nums::NegOne as i8;
+const NEG_ONE_I16: i16 = Nums::NegOne as i16;
+const NEG_ONE_I32: i32 = Nums::NegOne as i32;
+const NEG_ONE_I64: i64 = Nums::NegOne as i64;
+const NEG_ONE_I128: i128 = Nums::NegOne as i128;
+
+#[inline(never)]
+fn identity<T>(t: T) -> T { t }
+
+fn test_as_arg(n: Nums) {
+    assert_eq!(-1i8, n as i8);
+    assert_eq!(-1i16, n as i16);
+    assert_eq!(-1i32, n as i32);
+    assert_eq!(-1i64, n as i64);
+    assert_eq!(-1i128, n as i128);
+}
+
+fn main() {
+    let kind = Nums::NegOne;
+    assert_eq!(-1i8, kind as i8);
+    assert_eq!(-1i16, kind as i16);
+    assert_eq!(-1i32, kind as i32);
+    assert_eq!(-1i64, kind as i64);
+    assert_eq!(-1i128, kind as i128);
+
+    assert_eq!(-1i8, identity(kind) as i8);
+    assert_eq!(-1i16, identity(kind) as i16);
+    assert_eq!(-1i32, identity(kind) as i32);
+    assert_eq!(-1i64, identity(kind) as i64);
+    assert_eq!(-1i128, identity(kind) as i128);
+
+    test_as_arg(Nums::NegOne);
+
+    assert_eq!(-1i8, NEG_ONE_I8);
+    assert_eq!(-1i16, NEG_ONE_I16);
+    assert_eq!(-1i32, NEG_ONE_I32);
+    assert_eq!(-1i64, NEG_ONE_I64);
+    assert_eq!(-1i128, NEG_ONE_I128);
+}
diff --git a/src/test/ui/eprint-on-tls-drop.rs b/src/test/ui/eprint-on-tls-drop.rs
new file mode 100644 (file)
index 0000000..9c4800c
--- /dev/null
@@ -0,0 +1,48 @@
+// run-pass
+// ignore-emscripten no processes
+
+use std::cell::RefCell;
+use std::env;
+use std::process::Command;
+
+fn main() {
+    let name = "YOU_ARE_THE_TEST";
+    if env::var(name).is_ok() {
+        std::thread::spawn(|| {
+            TLS.with(|f| f.borrow().ensure());
+        })
+        .join()
+        .unwrap();
+    } else {
+        let me = env::current_exe().unwrap();
+        let output = Command::new(&me).env(name, "1").output().unwrap();
+        println!("{:?}", output);
+        assert!(output.status.success());
+        let stderr = String::from_utf8(output.stderr).unwrap();
+        assert!(stderr.contains("hello new\n"));
+        assert!(stderr.contains("hello drop\n"));
+    }
+}
+
+struct Stuff {
+    _x: usize,
+}
+
+impl Stuff {
+    fn new() -> Self {
+        eprintln!("hello new");
+        Self { _x: 0 }
+    }
+
+    fn ensure(&self) {}
+}
+
+impl Drop for Stuff {
+    fn drop(&mut self) {
+        eprintln!("hello drop");
+    }
+}
+
+thread_local! {
+    static TLS: RefCell<Stuff> = RefCell::new(Stuff::new());
+}
diff --git a/src/test/ui/issues/issue-70041.rs b/src/test/ui/issues/issue-70041.rs
new file mode 100644 (file)
index 0000000..22e4229
--- /dev/null
@@ -0,0 +1,13 @@
+// compile-flags: --edition=2018
+// run-pass
+
+macro_rules! regex {
+    //~^ WARN unused macro definition
+    () => {};
+}
+
+#[allow(dead_code)]
+use regex;
+//~^ WARN unused import
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-70041.stderr b/src/test/ui/issues/issue-70041.stderr
new file mode 100644 (file)
index 0000000..b180175
--- /dev/null
@@ -0,0 +1,19 @@
+warning: unused macro definition
+  --> $DIR/issue-70041.rs:4:1
+   |
+LL | / macro_rules! regex {
+LL | |
+LL | |     () => {};
+LL | | }
+   | |_^
+   |
+   = note: `#[warn(unused_macros)]` on by default
+
+warning: unused import: `regex`
+  --> $DIR/issue-70041.rs:10:5
+   |
+LL | use regex;
+   |     ^^^^^
+   |
+   = note: `#[warn(unused_imports)]` on by default
+
diff --git a/src/test/ui/layout/debug.rs b/src/test/ui/layout/debug.rs
new file mode 100644 (file)
index 0000000..70ae200
--- /dev/null
@@ -0,0 +1,15 @@
+// normalize-stderr-test "pref: Align \{\n *pow2: [1-3],\n *\}" -> "pref: $$PREF_ALIGN"
+#![feature(never_type, rustc_attrs)]
+#![crate_type = "lib"]
+
+#[rustc_layout(debug)]
+enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout debugging
+
+#[rustc_layout(debug)]
+struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout debugging
+
+#[rustc_layout(debug)]
+union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout debugging
+
+#[rustc_layout(debug)]
+type Test = Result<i32, i32>; //~ ERROR: layout debugging
diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr
new file mode 100644 (file)
index 0000000..0ce5382
--- /dev/null
@@ -0,0 +1,319 @@
+error: layout debugging: LayoutDetails {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+        ],
+        memory_index: [
+            0,
+        ],
+    },
+    variants: Multiple {
+        discr: Scalar {
+            value: Int(
+                I32,
+                false,
+            ),
+            valid_range: 0..=0,
+        },
+        discr_kind: Tag,
+        discr_index: 0,
+        variants: [
+            LayoutDetails {
+                fields: Arbitrary {
+                    offsets: [],
+                    memory_index: [],
+                },
+                variants: Single {
+                    index: 0,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 0,
+                    },
+                    pref: $PREF_ALIGN,
+                },
+                size: Size {
+                    raw: 4,
+                },
+            },
+            LayoutDetails {
+                fields: Arbitrary {
+                    offsets: [
+                        Size {
+                            raw: 4,
+                        },
+                        Size {
+                            raw: 4,
+                        },
+                        Size {
+                            raw: 8,
+                        },
+                    ],
+                    memory_index: [
+                        0,
+                        1,
+                        2,
+                    ],
+                },
+                variants: Single {
+                    index: 1,
+                },
+                abi: Uninhabited,
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 2,
+                    },
+                    pref: $PREF_ALIGN,
+                },
+                size: Size {
+                    raw: 12,
+                },
+            },
+        ],
+    },
+    abi: Aggregate {
+        sized: true,
+    },
+    largest_niche: Some(
+        Niche {
+            offset: Size {
+                raw: 0,
+            },
+            scalar: Scalar {
+                value: Int(
+                    I32,
+                    false,
+                ),
+                valid_range: 0..=0,
+            },
+        },
+    ),
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 2,
+        },
+        pref: $PREF_ALIGN,
+    },
+    size: Size {
+        raw: 12,
+    },
+}
+  --> $DIR/debug.rs:6:1
+   |
+LL | enum E { Foo, Bar(!, i32, i32) }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout debugging: LayoutDetails {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+            Size {
+                raw: 0,
+            },
+            Size {
+                raw: 4,
+            },
+        ],
+        memory_index: [
+            1,
+            0,
+            2,
+        ],
+    },
+    variants: Single {
+        index: 0,
+    },
+    abi: ScalarPair(
+        Scalar {
+            value: Int(
+                I32,
+                true,
+            ),
+            valid_range: 0..=4294967295,
+        },
+        Scalar {
+            value: Int(
+                I32,
+                true,
+            ),
+            valid_range: 0..=4294967295,
+        },
+    ),
+    largest_niche: None,
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 2,
+        },
+        pref: $PREF_ALIGN,
+    },
+    size: Size {
+        raw: 8,
+    },
+}
+  --> $DIR/debug.rs:9:1
+   |
+LL | struct S { f1: i32, f2: (), f3: i32 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout debugging: LayoutDetails {
+    fields: Union(
+        2,
+    ),
+    variants: Single {
+        index: 0,
+    },
+    abi: Aggregate {
+        sized: true,
+    },
+    largest_niche: None,
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 2,
+        },
+        pref: $PREF_ALIGN,
+    },
+    size: Size {
+        raw: 8,
+    },
+}
+  --> $DIR/debug.rs:12:1
+   |
+LL | union U { f1: (i32, i32), f3: i32 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout debugging: LayoutDetails {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+        ],
+        memory_index: [
+            0,
+        ],
+    },
+    variants: Multiple {
+        discr: Scalar {
+            value: Int(
+                I32,
+                false,
+            ),
+            valid_range: 0..=1,
+        },
+        discr_kind: Tag,
+        discr_index: 0,
+        variants: [
+            LayoutDetails {
+                fields: Arbitrary {
+                    offsets: [
+                        Size {
+                            raw: 4,
+                        },
+                    ],
+                    memory_index: [
+                        0,
+                    ],
+                },
+                variants: Single {
+                    index: 0,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 2,
+                    },
+                    pref: $PREF_ALIGN,
+                },
+                size: Size {
+                    raw: 8,
+                },
+            },
+            LayoutDetails {
+                fields: Arbitrary {
+                    offsets: [
+                        Size {
+                            raw: 4,
+                        },
+                    ],
+                    memory_index: [
+                        0,
+                    ],
+                },
+                variants: Single {
+                    index: 1,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 2,
+                    },
+                    pref: $PREF_ALIGN,
+                },
+                size: Size {
+                    raw: 8,
+                },
+            },
+        ],
+    },
+    abi: ScalarPair(
+        Scalar {
+            value: Int(
+                I32,
+                false,
+            ),
+            valid_range: 0..=1,
+        },
+        Scalar {
+            value: Int(
+                I32,
+                true,
+            ),
+            valid_range: 0..=4294967295,
+        },
+    ),
+    largest_niche: Some(
+        Niche {
+            offset: Size {
+                raw: 0,
+            },
+            scalar: Scalar {
+                value: Int(
+                    I32,
+                    false,
+                ),
+                valid_range: 0..=1,
+            },
+        },
+    ),
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 2,
+        },
+        pref: $PREF_ALIGN,
+    },
+    size: Size {
+        raw: 8,
+    },
+}
+  --> $DIR/debug.rs:15:1
+   |
+LL | type Test = Result<i32, i32>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
index 627d58abf4ca2aa55926c17bfb96d84cd908c92c..a55f05414b206c98f1a002859bdb0e444b152e2f 100644 (file)
@@ -13,7 +13,7 @@ macro_rules! pat_macro {
         pat_macro!(A{a:a, b:0, c:_, ..});
     };
     ($a:pat) => {
-        $a
+        $a //~ ERROR expected expression
     };
 }
 
index a18e22e07f8bcb5774c6797d1c231bb19c8739ab..109b493b43717e970268c315bf4e1afc07da8535 100644 (file)
@@ -49,5 +49,16 @@ LL |     my_recursive_macro!();
    = note: expanding `my_recursive_macro! {  }`
    = note: to `my_recursive_macro ! () ;`
 
-error: aborting due to 2 previous errors
+error: expected expression, found `A { a: a, b: 0, c: _, .. }`
+  --> $DIR/trace_faulty_macros.rs:16:9
+   |
+LL |         $a
+   |         ^^ expected expression
+...
+LL |     let a = pat_macro!();
+   |             ------------ in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
 
index d475c79cb27b4522a6ccbd33383a1c6e0ae5b23e..967eee06e282f94078d7fac788d82f6f589ba79e 100644 (file)
@@ -20,3 +20,4 @@ LL | type X<'a> = (?'a) +;
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0224`.
index 230733371ddd8a362efd512eb042126d82568a96..a6fa9f8dddc275df9a43de66e878d9b90630f037 100644 (file)
@@ -20,3 +20,4 @@ LL |     m!('static);
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/ui/parser/recover-quantified-closure.rs b/src/test/ui/parser/recover-quantified-closure.rs
new file mode 100644 (file)
index 0000000..3813247
--- /dev/null
@@ -0,0 +1,10 @@
+fn main() {
+    for<'a> |x: &'a u8| *x + 1;
+    //~^ ERROR cannot introduce explicit parameters for a closure
+}
+
+enum Foo { Bar }
+fn foo(x: impl Iterator<Item = Foo>) {
+    for <Foo>::Bar in x {}
+    //~^ ERROR expected one of `move`, `static`, `|`
+}
diff --git a/src/test/ui/parser/recover-quantified-closure.stderr b/src/test/ui/parser/recover-quantified-closure.stderr
new file mode 100644 (file)
index 0000000..0f01132
--- /dev/null
@@ -0,0 +1,16 @@
+error: cannot introduce explicit parameters for a closure
+  --> $DIR/recover-quantified-closure.rs:2:5
+   |
+LL |     for<'a> |x: &'a u8| *x + 1;
+   |     ^^^^^^^ ------------------ the parameters are attached to this closure
+   |     |
+   |     help: remove the parameters
+
+error: expected one of `move`, `static`, `|`, or `||`, found `::`
+  --> $DIR/recover-quantified-closure.rs:8:14
+   |
+LL |     for <Foo>::Bar in x {}
+   |              ^^ expected one of `move`, `static`, `|`, or `||`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/proc-macro/out-of-line-mod.rs b/src/test/ui/proc-macro/out-of-line-mod.rs
new file mode 100644 (file)
index 0000000..658ed6c
--- /dev/null
@@ -0,0 +1,13 @@
+// Out-of-line module is found on the filesystem if passed through a proc macro (issue #58818).
+
+// check-pass
+// aux-build:test-macros.rs
+
+#[macro_use]
+extern crate test_macros;
+
+mod outer {
+    identity! { mod inner; }
+}
+
+fn main() {}
index 6de79fa917b16d704f3ba6e3aa21475755a9dfb2..594115d980c8b54a2d66ffe4e2e96e7aa2141b16 100644 (file)
@@ -12,3 +12,4 @@ LL | type _T1 = dyn _2;
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0224`.
index a8511f63c16a5ac9d1e88519cc2b397a926b6eac..cb48bd1258ea2f4ebb5fbb7b014d9f63ea0c747f 100644 (file)
@@ -14,4 +14,5 @@ LL |     m!(dyn Copy + Send + 'static);
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0038`.
+Some errors have detailed explanations: E0038, E0224.
+For more information about an error, try `rustc --explain E0038`.
index 014d380b63ca5c05dedb798944d9819ff32053a6..28b8e11f1330c89dff348b69a8f11e56afeeb033 100644 (file)
@@ -6,3 +6,4 @@ LL |     dyn 'static +: 'static + Copy,
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0224`.
index 04529fb8cfab3caa1e61ddf2519acd2d91a55be3..ff3fc2a197c66bbe4bede56bbc8095bd37c20efe 100644 (file)
@@ -32,5 +32,5 @@ LL |     let _: S<dyn 'static +, 'static>;
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0107, E0747.
+Some errors have detailed explanations: E0107, E0224, E0747.
 For more information about an error, try `rustc --explain E0107`.
index 8cc97addc7dd4a832119c0f52587f5e320e5d6ca..482410886329e1989fe4dbd09eeabbfcc1f07f83 100644 (file)
@@ -12,3 +12,4 @@ LL | type _0 = dyn ?Sized;
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0224`.
index 23549a8c362a403026432f65a6cb398cb10d44b7..d8e6e4cfcd83d555bd7717ea24224b777ed75773 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 23549a8c362a403026432f65a6cb398cb10d44b7
+Subproject commit d8e6e4cfcd83d555bd7717ea24224b777ed75773