]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #95530 - notriddle:notriddle/private-kw-prim, r=jsha
authorMatthias Krüger <matthias.krueger@famsik.de>
Fri, 1 Apr 2022 04:59:45 +0000 (06:59 +0200)
committerGitHub <noreply@github.com>
Fri, 1 Apr 2022 04:59:45 +0000 (06:59 +0200)
rustdoc: do not show primitives and keywords as private

Fixes this:

![image](https://user-images.githubusercontent.com/1593513/161102430-f1f0301e-3e7f-453f-9c0a-bc87a12b893d.png)

57 files changed:
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/traits.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_infer/src/infer/at.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_middle/src/mir/interpret/pointer.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/closure.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_ty_utils/src/representability.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
compiler/rustc_typeck/src/check/inherited.rs
compiler/rustc_typeck/src/check/wfcheck.rs
library/core/src/ptr/mod.rs
library/core/src/sync/atomic.rs
library/std/src/lib.rs
src/librustdoc/clean/types.rs
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.rs
src/test/ui/consts/const-size_of_val-align_of_val.rs
src/test/ui/did_you_mean/brackets-to-braces-single-element.rs [new file with mode: 0644]
src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr [new file with mode: 0644]
src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs
src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr
src/test/ui/issues/issue-17431-1.stderr
src/test/ui/issues/issue-17431-2.stderr
src/test/ui/issues/issue-17431-4.stderr
src/test/ui/issues/issue-17431-7.stderr
src/test/ui/issues/issue-3779.stderr
src/test/ui/issues/issue-59494.stderr
src/test/ui/sized-cycle-note.stderr
src/test/ui/span/E0072.stderr
src/test/ui/span/multiline-span-E0072.stderr
src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr
src/test/ui/trait-bounds/mismatch-fn-trait.rs [new file with mode: 0644]
src/test/ui/trait-bounds/mismatch-fn-trait.stderr [new file with mode: 0644]
src/test/ui/type/type-recursive-box-shadowed.rs [new file with mode: 0644]
src/test/ui/type/type-recursive-box-shadowed.stderr [new file with mode: 0644]
src/test/ui/type/type-recursive.rs
src/test/ui/type/type-recursive.stderr
src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr

index 1784e4a6c63a8cb0d9e2ff3731e96af2bf259f9b..c8fd96309a6cd3bac49a1e8ed7729880465ca6d2 100644 (file)
@@ -1,16 +1,19 @@
 use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
-use super::{ImplTraitContext, ImplTraitPosition};
+use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
 use crate::{Arena, FnDeclKind};
 
 use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
+use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::LocalDefId;
-use rustc_index::vec::Idx;
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_session::utils::NtToTokenstream;
+use rustc_session::Session;
 use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use tracing::debug;
 
 use std::iter;
-use std::mem;
 
-pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
-    pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
+pub(super) struct ItemLowerer<'a, 'hir> {
+    pub(super) sess: &'a Session,
+    pub(super) resolver: &'a mut dyn ResolverAstLowering,
+    pub(super) nt_to_tokenstream: NtToTokenstream,
+    pub(super) arena: &'hir Arena<'hir>,
+    pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
+    pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 }
 
 /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
@@ -45,130 +52,140 @@ fn add_ty_alias_where_clause(
     }
 }
 
-impl ItemLowerer<'_, '_, '_> {
-    fn with_trait_impl_ref<T>(
+impl<'a, 'hir> ItemLowerer<'a, 'hir> {
+    fn with_lctx(
         &mut self,
-        impl_ref: &Option<TraitRef>,
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
-        let old = self.lctx.is_in_trait_impl;
-        self.lctx.is_in_trait_impl = impl_ref.is_some();
-        let ret = f(self);
-        self.lctx.is_in_trait_impl = old;
-        ret
-    }
-}
-
-impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
-    fn visit_attribute(&mut self, _: &'a Attribute) {
-        // We do not want to lower expressions that appear in attributes,
-        // as they are not accessible to the rest of the HIR.
-    }
+        owner: NodeId,
+        f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
+    ) {
+        let mut lctx = LoweringContext {
+            // Pseudo-globals.
+            sess: &self.sess,
+            resolver: self.resolver,
+            nt_to_tokenstream: self.nt_to_tokenstream,
+            arena: self.arena,
+
+            // HirId handling.
+            bodies: Vec::new(),
+            attrs: SortedMap::default(),
+            children: FxHashMap::default(),
+            current_hir_id_owner: CRATE_DEF_ID,
+            item_local_id_counter: hir::ItemLocalId::new(0),
+            node_id_to_local_id: Default::default(),
+            local_id_to_def_id: SortedMap::new(),
+            trait_map: Default::default(),
+
+            // Lowering state.
+            catch_scope: None,
+            loop_scope: None,
+            is_in_loop_condition: false,
+            is_in_trait_impl: false,
+            is_in_dyn_type: false,
+            anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
+            generator_kind: None,
+            task_context: None,
+            current_item: None,
+            lifetimes_to_define: Vec::new(),
+            is_collecting_anonymous_lifetimes: None,
+            in_scope_lifetimes: Vec::new(),
+            allow_try_trait: Some([sym::try_trait_v2][..].into()),
+            allow_gen_future: Some([sym::gen_future][..].into()),
+            allow_into_future: Some([sym::into_future][..].into()),
+        };
+        lctx.with_hir_id_owner(owner, |lctx| f(lctx));
 
-    fn visit_item(&mut self, item: &'a Item) {
-        let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
-            let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
-            hir::OwnerNode::Item(node)
-        });
-
-        self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
-            let this = &mut ItemLowerer { lctx: this };
-            match item.kind {
-                ItemKind::Impl(box Impl { ref of_trait, .. }) => {
-                    this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
-                }
-                _ => visit::walk_item(this, item),
-            }
-        });
+        for (def_id, info) in lctx.children {
+            self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+            debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom));
+            self.owners[def_id] = info;
+        }
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
-        match fk {
-            FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => {
-                self.visit_fn_header(&sig.header);
-                visit::walk_fn_decl(self, &sig.decl);
-                // Don't visit the foreign function body even if it has one, since lowering the
-                // body would have no meaning and will have already been caught as a parse error.
+    pub(super) fn lower_node(
+        &mut self,
+        def_id: LocalDefId,
+    ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
+        self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+        if let hir::MaybeOwner::Phantom = self.owners[def_id] {
+            let node = self.ast_index[def_id];
+            match node {
+                AstOwner::NonOwner => {}
+                AstOwner::Crate(c) => self.lower_crate(c),
+                AstOwner::Item(item) => self.lower_item(item),
+                AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt),
+                AstOwner::ForeignItem(item) => self.lower_foreign_item(item),
             }
-            _ => visit::walk_fn(self, fk, sp),
         }
-    }
-
-    fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
-        debug!(in_scope_lifetimes = ?self.lctx.in_scope_lifetimes);
-        self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
-            AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
-            AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
-        });
 
-        visit::walk_assoc_item(self, item, ctxt);
+        self.owners[def_id]
     }
 
-    fn visit_foreign_item(&mut self, item: &'a ForeignItem) {
-        self.lctx.with_hir_id_owner(item.id, |lctx| {
-            hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))
-        });
+    fn lower_crate(&mut self, c: &Crate) {
+        debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
 
-        visit::walk_foreign_item(self, item);
+        self.with_lctx(CRATE_NODE_ID, |lctx| {
+            let module = lctx.lower_mod(&c.items, c.spans.inner_span);
+            lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
+            hir::OwnerNode::Crate(lctx.arena.alloc(module))
+        })
     }
-}
 
-impl<'hir> LoweringContext<'_, 'hir> {
-    // Same as the method above, but accepts `hir::GenericParam`s
-    // instead of `ast::GenericParam`s.
-    // This should only be used with generics that have already had their
-    // in-band lifetimes added. In practice, this means that this function is
-    // only used when lowering a child item of a trait or impl.
-    #[tracing::instrument(level = "debug", skip(self, f))]
-    fn with_parent_item_lifetime_defs<T>(
-        &mut self,
-        parent_hir_id: LocalDefId,
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
-        let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind {
-            hir::ItemKind::Impl(hir::Impl { ref generics, .. })
-            | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
-            _ => &[],
-        };
-        let lt_def_names = parent_generics
-            .iter()
-            .filter_map(|param| match param.kind {
-                hir::GenericParamKind::Lifetime { .. } => {
-                    Some(param.name.normalize_to_macros_2_0())
-                }
-                _ => None,
-            })
-            .collect();
-        let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, lt_def_names);
-        debug!(in_scope_lifetimes = ?self.in_scope_lifetimes);
-
-        let res = f(self);
-
-        self.in_scope_lifetimes = old_in_scope_lifetimes;
-        res
+    fn lower_item(&mut self, item: &Item) {
+        self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
     }
 
-    // Clears (and restores) the `in_scope_lifetimes` field. Used when
-    // visiting nested items, which never inherit in-scope lifetimes
-    // from their surrounding environment.
-    #[tracing::instrument(level = "debug", skip(self, f))]
-    fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
-        let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
-        debug!(?old_in_scope_lifetimes);
+    fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
+        let def_id = self.resolver.local_def_id(item.id);
 
-        // this vector is only used when walking over impl headers,
-        // input types, and the like, and should not be non-empty in
-        // between items
-        assert!(self.lifetimes_to_define.is_empty());
+        let parent_id = {
+            let parent = self.resolver.definitions().def_key(def_id).parent;
+            let local_def_index = parent.unwrap();
+            LocalDefId { local_def_index }
+        };
 
-        let res = f(self);
+        let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item();
+        self.with_lctx(item.id, |lctx| {
+            // Evaluate with the lifetimes in `params` in-scope.
+            // This is used to track which lifetimes have already been defined,
+            // and which need to be replicated when lowering an async fn.
+            match parent_hir.kind {
+                hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => {
+                    lctx.is_in_trait_impl = of_trait.is_some();
+                    lctx.in_scope_lifetimes = generics
+                        .params
+                        .iter()
+                        .filter(|param| {
+                            matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
+                        })
+                        .map(|param| param.name)
+                        .collect();
+                }
+                hir::ItemKind::Trait(_, _, ref generics, ..) => {
+                    lctx.in_scope_lifetimes = generics
+                        .params
+                        .iter()
+                        .filter(|param| {
+                            matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
+                        })
+                        .map(|param| param.name)
+                        .collect();
+                }
+                _ => {}
+            };
 
-        assert!(self.in_scope_lifetimes.is_empty());
-        self.in_scope_lifetimes = old_in_scope_lifetimes;
+            match ctxt {
+                AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
+                AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
+            }
+        })
+    }
 
-        res
+    fn lower_foreign_item(&mut self, item: &ForeignItem) {
+        self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
     }
+}
 
+impl<'hir> LoweringContext<'_, 'hir> {
     pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
         hir::Mod {
             inner: self.lower_span(inner),
@@ -548,12 +565,11 @@ fn lower_use_tree(
                     let new_id = self.resolver.local_def_id(new_node_id);
                     let Some(res) = resolutions.next() else {
                         // Associate an HirId to both ids even if there is no resolution.
-                        self.owners.ensure_contains_elem(new_id, || hir::MaybeOwner::Phantom);
-                        let _old = std::mem::replace(
-                            &mut self.owners[new_id],
+                        let _old = self.children.insert(
+                            new_id,
                             hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id)),
                         );
-                        debug_assert!(matches!(_old, hir::MaybeOwner::Phantom));
+                        debug_assert!(_old.is_none());
                         continue;
                     };
                     let ident = *ident;
index d684a0e67e20b4d7ab6896208c04f653ded74c15..e4ed48d4b530d673e0adca9c5038c4bcc67fa112 100644 (file)
@@ -57,7 +57,6 @@
 use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
-use rustc_session::lint::LintBuffer;
 use rustc_session::parse::feature_err;
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
@@ -100,12 +99,12 @@ struct LoweringContext<'a, 'hir: 'a> {
     /// Used to allocate HIR nodes.
     arena: &'hir Arena<'hir>,
 
-    /// The items being lowered are collected here.
-    owners: IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
     /// Attributes inside the owner being lowered.
     attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
+    /// Collect items that were created by lowering the current owner.
+    children: FxHashMap<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 
     generator_kind: Option<hir::GeneratorKind>,
 
@@ -159,7 +158,7 @@ struct LoweringContext<'a, 'hir: 'a> {
 }
 
 pub trait ResolverAstLowering {
-    fn def_key(&mut self, id: DefId) -> DefKey;
+    fn def_key(&self, id: DefId) -> DefKey;
 
     fn def_span(&self, id: LocalDefId) -> Span;
 
@@ -171,18 +170,14 @@ pub trait ResolverAstLowering {
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
 
     /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
-    fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
+    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
 
     /// Obtains resolution for a label with the given `NodeId`.
-    fn get_label_res(&mut self, id: NodeId) -> Option<NodeId>;
-
-    /// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
-    /// This should only return `None` during testing.
-    fn definitions(&mut self) -> &mut Definitions;
+    fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
 
     fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
 
-    fn lint_buffer(&mut self) -> &mut LintBuffer;
+    fn definitions(&self) -> &Definitions;
 
     fn next_node_id(&mut self) -> NodeId;
 
@@ -337,6 +332,81 @@ fn impl_trait_return_allowed(&self) -> bool {
     }
 }
 
+#[derive(Copy, Clone)]
+enum AstOwner<'a> {
+    NonOwner,
+    Crate(&'a ast::Crate),
+    Item(&'a ast::Item),
+    AssocItem(&'a ast::AssocItem, visit::AssocCtxt),
+    ForeignItem(&'a ast::ForeignItem),
+}
+
+fn index_crate<'a>(
+    resolver: &dyn ResolverAstLowering,
+    krate: &'a Crate,
+) -> IndexVec<LocalDefId, AstOwner<'a>> {
+    let mut indexer = Indexer { resolver, index: IndexVec::new() };
+    indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner);
+    indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate);
+    visit::walk_crate(&mut indexer, krate);
+    return indexer.index;
+
+    struct Indexer<'s, 'a> {
+        resolver: &'s dyn ResolverAstLowering,
+        index: IndexVec<LocalDefId, AstOwner<'a>>,
+    }
+
+    impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> {
+        fn visit_attribute(&mut self, _: &'a Attribute) {
+            // We do not want to lower expressions that appear in attributes,
+            // as they are not accessible to the rest of the HIR.
+        }
+
+        fn visit_item(&mut self, item: &'a ast::Item) {
+            let def_id = self.resolver.local_def_id(item.id);
+            self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
+            self.index[def_id] = AstOwner::Item(item);
+            visit::walk_item(self, item)
+        }
+
+        fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
+            let def_id = self.resolver.local_def_id(item.id);
+            self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
+            self.index[def_id] = AstOwner::AssocItem(item, ctxt);
+            visit::walk_assoc_item(self, item, ctxt);
+        }
+
+        fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
+            let def_id = self.resolver.local_def_id(item.id);
+            self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
+            self.index[def_id] = AstOwner::ForeignItem(item);
+            visit::walk_foreign_item(self, item);
+        }
+    }
+}
+
+/// Compute the hash for the HIR of the full crate.
+/// This hash will then be part of the crate_hash which is stored in the metadata.
+fn compute_hir_hash(
+    resolver: &mut dyn ResolverAstLowering,
+    owners: &IndexVec<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
+) -> Fingerprint {
+    let mut hir_body_nodes: Vec<_> = owners
+        .iter_enumerated()
+        .filter_map(|(def_id, info)| {
+            let info = info.as_owner()?;
+            let def_path_hash = resolver.definitions().def_path_hash(def_id);
+            Some((def_path_hash, info))
+        })
+        .collect();
+    hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+
+    let mut stable_hasher = StableHasher::new();
+    let mut hcx = resolver.create_stable_hashing_context();
+    hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
+    stable_hasher.finish()
+}
+
 pub fn lower_crate<'a, 'hir>(
     sess: &'a Session,
     krate: &'a Crate,
@@ -346,38 +416,26 @@ pub fn lower_crate<'a, 'hir>(
 ) -> &'hir hir::Crate<'hir> {
     let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
 
-    let owners =
+    let ast_index = index_crate(resolver, krate);
+
+    let mut owners =
         IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count());
-    LoweringContext {
-        sess,
-        resolver,
-        nt_to_tokenstream,
-        arena,
-        owners,
-        bodies: Vec::new(),
-        attrs: SortedMap::new(),
-        catch_scope: None,
-        loop_scope: None,
-        is_in_loop_condition: false,
-        is_in_trait_impl: false,
-        is_in_dyn_type: false,
-        anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
-        current_hir_id_owner: CRATE_DEF_ID,
-        item_local_id_counter: hir::ItemLocalId::new(0),
-        node_id_to_local_id: FxHashMap::default(),
-        local_id_to_def_id: SortedMap::new(),
-        trait_map: FxHashMap::default(),
-        generator_kind: None,
-        task_context: None,
-        current_item: None,
-        lifetimes_to_define: Vec::new(),
-        is_collecting_anonymous_lifetimes: None,
-        in_scope_lifetimes: Vec::new(),
-        allow_try_trait: Some([sym::try_trait_v2][..].into()),
-        allow_gen_future: Some([sym::gen_future][..].into()),
-        allow_into_future: Some([sym::into_future][..].into()),
-    }
-    .lower_crate(krate)
+
+    for def_id in ast_index.indices() {
+        item::ItemLowerer {
+            sess,
+            resolver,
+            nt_to_tokenstream,
+            arena,
+            ast_index: &ast_index,
+            owners: &mut owners,
+        }
+        .lower_node(def_id);
+    }
+
+    let hir_hash = compute_hir_hash(resolver, &owners);
+    let krate = hir::Crate { owners, hir_hash };
+    arena.alloc(krate)
 }
 
 #[derive(Copy, Clone, PartialEq)]
@@ -446,49 +504,11 @@ enum AnonymousLifetimeMode {
 }
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
-        debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
-
-        visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
-
-        self.with_hir_id_owner(CRATE_NODE_ID, |lctx| {
-            let module = lctx.lower_mod(&c.items, c.spans.inner_span);
-            lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
-            hir::OwnerNode::Crate(lctx.arena.alloc(module))
-        });
-
-        let hir_hash = self.compute_hir_hash();
-
-        let krate = hir::Crate { owners: self.owners, hir_hash };
-        self.arena.alloc(krate)
-    }
-
-    /// Compute the hash for the HIR of the full crate.
-    /// This hash will then be part of the crate_hash which is stored in the metadata.
-    fn compute_hir_hash(&mut self) -> Fingerprint {
-        let definitions = self.resolver.definitions();
-        let mut hir_body_nodes: Vec<_> = self
-            .owners
-            .iter_enumerated()
-            .filter_map(|(def_id, info)| {
-                let info = info.as_owner()?;
-                let def_path_hash = definitions.def_path_hash(def_id);
-                Some((def_path_hash, info))
-            })
-            .collect();
-        hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
-
-        let mut stable_hasher = StableHasher::new();
-        let mut hcx = self.resolver.create_stable_hashing_context();
-        hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
-        stable_hasher.finish()
-    }
-
     fn with_hir_id_owner(
         &mut self,
         owner: NodeId,
         f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
-    ) -> LocalDefId {
+    ) {
         let def_id = self.resolver.local_def_id(owner);
 
         let current_attrs = std::mem::take(&mut self.attrs);
@@ -516,15 +536,15 @@ fn with_hir_id_owner(
         self.current_hir_id_owner = current_owner;
         self.item_local_id_counter = current_local_counter;
 
-        self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
-        self.owners[def_id] = hir::MaybeOwner::Owner(self.arena.alloc(info));
-
-        def_id
+        let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info));
+        debug_assert!(_old.is_none())
     }
 
-    fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
+    fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
+        let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
+        let trait_map = std::mem::take(&mut self.trait_map);
 
         #[cfg(debug_assertions)]
         for (id, attrs) in attrs.iter() {
@@ -544,7 +564,7 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir
             hash_without_bodies,
             nodes,
             bodies,
-            local_id_to_def_id: std::mem::take(&mut self.local_id_to_def_id),
+            local_id_to_def_id,
         };
         let attrs = {
             let mut hcx = self.resolver.create_stable_hashing_context();
@@ -554,7 +574,7 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir
             hir::AttributeMap { map: attrs, hash }
         };
 
-        hir::OwnerInfo { nodes, parenting, attrs, trait_map: std::mem::take(&mut self.trait_map) }
+        self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
     }
 
     /// Hash the HIR node twice, one deep and one shallow hash.  This allows to differentiate
@@ -602,11 +622,8 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
 
                 assert_ne!(local_id, hir::ItemLocalId::new(0));
                 if let Some(def_id) = self.resolver.opt_local_def_id(ast_node_id) {
-                    self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
-                    if let o @ hir::MaybeOwner::Phantom = &mut self.owners[def_id] {
-                        // Do not override a `MaybeOwner::Owner` that may already here.
-                        *o = hir::MaybeOwner::NonOwner(hir_id);
-                    }
+                    // Do not override a `MaybeOwner::Owner` that may already here.
+                    self.children.entry(def_id).or_insert(hir::MaybeOwner::NonOwner(hir_id));
                     self.local_id_to_def_id.insert(local_id, def_id);
                 }
 
index 0b9d0a0e9220b29c9f6779a146e89fc6f164d825..f8439d2e163559f5c51faa2364f18c15b2dc1aed 100644 (file)
@@ -253,8 +253,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                // We add implied bounds from both the unnormalized and normalized ty
-                // See issue #87748
+                // We only add implied bounds for the normalized type as the unnormalized
+                // type may not actually get checked by the caller.
+                //
+                // Can otherwise be unsound, see #91068.
                 let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
index 7dc292ffb6579dfc9dcaaa11b75735ab90062f12..e9fa33f656f31006b12a39d0536091830056e4f6 100644 (file)
@@ -1899,7 +1899,9 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                                     ObligationCause::new(
                                         span,
                                         self.tcx().hir().local_def_id_to_hir_id(def_id),
-                                        traits::ObligationCauseCode::RepeatVec(is_const_fn),
+                                        traits::ObligationCauseCode::RepeatElementCopy {
+                                            is_const_fn,
+                                        },
                                     ),
                                     self.param_env,
                                     ty::Binder::dummy(ty::TraitRef::new(
index abd7094440e57c2a1aac6ba98d2e5e3ef740c8b8..1b8186b5aadbace598262cae23a4f7141c40f1fd 100644 (file)
@@ -23,8 +23,8 @@
 
 use super::{
     AllocCheck, AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine,
-    MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance,
-    Scalar, ScalarMaybeUninit, StackPopJump,
+    MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer,
+    PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, StackPopJump,
 };
 use crate::transform::validate::equal_up_to_regions;
 
@@ -678,7 +678,7 @@ pub(super) fn size_and_align_of(
                 let size = size.align_to(align);
 
                 // Check if this brought us over the size limit.
-                if size.bytes() >= self.tcx.data_layout.obj_size_bound() {
+                if size > self.max_size_of_val() {
                     throw_ub!(InvalidMeta("total size is bigger than largest supported object"));
                 }
                 Ok(Some((size, align)))
@@ -694,9 +694,11 @@ pub(super) fn size_and_align_of(
                 let elem = layout.field(self, 0);
 
                 // Make sure the slice is not too big.
-                let size = elem.size.checked_mul(len, self).ok_or_else(|| {
-                    err_ub!(InvalidMeta("slice is bigger than largest supported object"))
-                })?;
+                let size = elem.size.bytes().saturating_mul(len); // we rely on `max_size_of_val` being smaller than `u64::MAX`.
+                let size = Size::from_bytes(size);
+                if size > self.max_size_of_val() {
+                    throw_ub!(InvalidMeta("slice is bigger than largest supported object"));
+                }
                 Ok(Some((size, elem.align.abi)))
             }
 
index 5eff7d693c5a6dfe2bdc5c40aadca9f6159835f7..c80d7d71787422ced418d9ea410c8c012ecd81cb 100644 (file)
@@ -531,7 +531,9 @@ pub fn ptr_offset_inbounds(
     ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
         // We cannot overflow i64 as a type's size must be <= isize::MAX.
         let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
-        // The computed offset, in bytes, cannot overflow an isize.
+        // The computed offset, in bytes, must not overflow an isize.
+        // `checked_mul` enforces a too small bound, but no actual allocation can be big enough for
+        // the difference to be noticeable.
         let offset_bytes =
             offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
         // The offset being in bounds cannot rely on "wrapping around" the address space.
@@ -563,6 +565,8 @@ pub(crate) fn copy_intrinsic(
         let count = self.read_scalar(&count)?.to_machine_usize(self)?;
         let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
         let (size, align) = (layout.size, layout.align.abi);
+        // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
+        // but no actual allocation can be big enough for the difference to be noticeable.
         let size = size.checked_mul(count, self).ok_or_else(|| {
             err_ub_format!(
                 "overflow computing total size of `{}`",
@@ -588,6 +592,8 @@ pub(crate) fn write_bytes_intrinsic(
         let byte = self.read_scalar(&byte)?.to_u8()?;
         let count = self.read_scalar(&count)?.to_machine_usize(self)?;
 
+        // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
+        // but no actual allocation can be big enough for the difference to be noticeable.
         let len = layout
             .size
             .checked_mul(count, self)
index 131674decc96109087069099fa4c2df6ada2e10c..fc60a40e2ada6253881d91284c8fea91b833ae95 100644 (file)
@@ -110,16 +110,17 @@ pub fn read_size_and_align_from_vtable(
             .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
             .check_init()?;
         let size = size.to_machine_usize(self)?;
+        let size = Size::from_bytes(size);
         let align = vtable
             .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
             .check_init()?;
         let align = align.to_machine_usize(self)?;
         let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
 
-        if size >= self.tcx.data_layout.obj_size_bound() {
+        if size > self.max_size_of_val() {
             throw_ub!(InvalidVtableSize);
         }
-        Ok((Size::from_bytes(size), align))
+        Ok((size, align))
     }
 
     pub fn read_new_vtable_after_trait_upcasting_from_vtable(
index 1ff9395c5892b719b3c4604a73402a9de848779e..c62d3b9be2fcc327aea251ee4c89b39188e43ca3 100644 (file)
@@ -99,6 +99,7 @@ pub fn enumerated_keys_and_path_hashes(
 #[derive(Clone, Debug)]
 pub struct Definitions {
     table: DefPathTable,
+    next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
 
     /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
     expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
@@ -340,6 +341,7 @@ pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
 
         Definitions {
             table,
+            next_disambiguator: Default::default(),
             expansions_that_defined: Default::default(),
             def_id_to_span,
             stable_crate_id,
@@ -357,7 +359,6 @@ pub fn create_def(
         parent: LocalDefId,
         data: DefPathData,
         expn_id: ExpnId,
-        mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
         span: Span,
     ) -> LocalDefId {
         debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
@@ -365,7 +366,13 @@ pub fn create_def(
         // The root node must be created with `create_root_def()`.
         assert!(data != DefPathData::CrateRoot);
 
-        let disambiguator = next_disambiguator(parent, data);
+        // Find the next free disambiguator for this key.
+        let disambiguator = {
+            let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
+            let disambiguator = *next_disamb;
+            *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
+            disambiguator
+        };
         let key = DefKey {
             parent: Some(parent.local_def_index),
             disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
index 71ee4f1e76d6d01fe5aa47e174ff8b1fc3cd5d6c..09b02ba74a8de0d079cdaebe2533497025d95745 100644 (file)
@@ -65,7 +65,6 @@ pub fn fork(&self) -> Self {
         Self {
             tcx: self.tcx.clone(),
             defining_use_anchor: self.defining_use_anchor.clone(),
-            reveal_defining_opaque_types: self.reveal_defining_opaque_types.clone(),
             in_progress_typeck_results: self.in_progress_typeck_results.clone(),
             inner: self.inner.clone(),
             skip_leak_check: self.skip_leak_check.clone(),
index 9b2fc07e9cbe4e930dcf8e1eb91dd89e98748c1d..d915f9a5ae83c40e50304d5622890dcfda0c9a42 100644 (file)
@@ -1091,7 +1091,11 @@ fn cmp_fn_sig(
 
     /// Compares two given types, eliding parts that are the same between them and highlighting
     /// relevant differences, and return two representation of those types for highlighted printing.
-    fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) {
+    pub fn cmp(
+        &self,
+        t1: Ty<'tcx>,
+        t2: Ty<'tcx>,
+    ) -> (DiagnosticStyledString, DiagnosticStyledString) {
         debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind());
 
         // helper functions
index a9b4451e77b08ce0d6d5adac91a98e50572d3d21..bd59bf4dea8837c552f9225b433a59dfc94b2e6c 100644 (file)
@@ -290,10 +290,6 @@ pub struct InferCtxt<'a, 'tcx> {
     /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
     pub defining_use_anchor: Option<LocalDefId>,
 
-    /// Used by WF-checking to not have to figure out hidden types itself, but
-    /// to just invoke type_of to get the already computed hidden type from typeck.
-    pub reveal_defining_opaque_types: bool,
-
     /// During type-checking/inference of a body, `in_progress_typeck_results`
     /// contains a reference to the typeck results being built up, which are
     /// used for reading closure kinds/signatures as they are inferred,
@@ -569,7 +565,6 @@ pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
     defining_use_anchor: Option<LocalDefId>,
-    reveal_defining_opaque_types: bool,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -578,12 +573,7 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder {
-            tcx: self,
-            defining_use_anchor: None,
-            fresh_typeck_results: None,
-            reveal_defining_opaque_types: false,
-        }
+        InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
     }
 }
 
@@ -607,13 +597,6 @@ pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) ->
         self
     }
 
-    /// WF-checking doesn't need to recompute opaque types and can instead use
-    /// the type_of query to get them from typeck.
-    pub fn reveal_defining_opaque_types(mut self) -> Self {
-        self.reveal_defining_opaque_types = true;
-        self
-    }
-
     /// Given a canonical value `C` as a starting point, create an
     /// inference context that contains each of the bound values
     /// within instantiated as a fresh variable. The `f` closure is
@@ -638,17 +621,11 @@ pub fn enter_with_canonical<T, R>(
     }
 
     pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder {
-            tcx,
-            defining_use_anchor,
-            reveal_defining_opaque_types,
-            ref fresh_typeck_results,
-        } = *self;
+        let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
         let in_progress_typeck_results = fresh_typeck_results.as_ref();
         f(InferCtxt {
             tcx,
             defining_use_anchor,
-            reveal_defining_opaque_types,
             in_progress_typeck_results,
             inner: RefCell::new(InferCtxtInner::new()),
             lexical_region_resolutions: RefCell::new(None),
index ea4955e9a549a0bf51f315e7a16ba65b16d9ff07..f2164bccc3e9b1855ac6a3eb24120f75755ad893 100644 (file)
@@ -487,12 +487,24 @@ pub fn configure_and_expand(
         }
     });
 
+    sess.time("early_lint_checks", || {
+        let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
+        rustc_lint::check_ast_node(
+            sess,
+            false,
+            lint_store,
+            resolver.registered_tools(),
+            lint_buffer,
+            rustc_lint::BuiltinCombinedEarlyLintPass::new(),
+            &krate,
+        )
+    });
+
     Ok(krate)
 }
 
 pub fn lower_to_hir<'res, 'tcx>(
     sess: &'tcx Session,
-    lint_store: &LintStore,
     resolver: &'res mut Resolver<'_>,
     krate: Rc<ast::Crate>,
     arena: &'tcx rustc_ast_lowering::Arena<'tcx>,
@@ -506,19 +518,6 @@ pub fn lower_to_hir<'res, 'tcx>(
         arena,
     );
 
-    sess.time("early_lint_checks", || {
-        let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
-        rustc_lint::check_ast_node(
-            sess,
-            false,
-            lint_store,
-            resolver.registered_tools(),
-            lint_buffer,
-            rustc_lint::BuiltinCombinedEarlyLintPass::new(),
-            &*krate,
-        )
-    });
-
     // Drop AST to free memory
     sess.time("drop_ast", || std::mem::drop(krate));
 
@@ -852,9 +851,8 @@ pub fn create_global_ctxt<'tcx>(
     dep_graph.assert_ignored();
 
     let sess = &compiler.session();
-    let krate = resolver
-        .borrow_mut()
-        .access(|resolver| lower_to_hir(sess, &lint_store, resolver, krate, hir_arena));
+    let krate =
+        resolver.borrow_mut().access(|resolver| lower_to_hir(sess, resolver, krate, hir_arena));
     let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver);
 
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
index 7d101046a96b48b67f2fdd65e7f8c434bb15a497..813c0912f539679db80f57d1ec455580c0ccb1de 100644 (file)
@@ -18,6 +18,11 @@ fn pointer_size(&self) -> Size {
         self.data_layout().pointer_size
     }
 
+    #[inline(always)]
+    fn max_size_of_val(&self) -> Size {
+        Size::from_bytes(self.machine_isize_max())
+    }
+
     #[inline]
     fn machine_usize_max(&self) -> u64 {
         self.pointer_size().unsigned_int_max().try_into().unwrap()
index 3d0a0d2a58e1f907b07e0c9c4d1c55f4532847ef..1f18260d9154f52929ea480d70e87dcbfeca8af3 100644 (file)
@@ -236,11 +236,12 @@ pub enum ObligationCauseCode<'tcx> {
     SizedBoxType,
     /// Inline asm operand type must be `Sized`.
     InlineAsmSized,
-    /// `[T, ..n]` implies that `T` must be `Copy`.
-    /// If the function in the array repeat expression is a `const fn`,
-    /// display a help message suggesting to move the function call to a
-    /// new `const` item while saying that `T` doesn't implement `Copy`.
-    RepeatVec(bool),
+    /// `[expr; N]` requires `type_of(expr): Copy`.
+    RepeatElementCopy {
+        /// If element is a `const fn` we display a help message suggesting to move the
+        /// function call to a new `const` item while saying that `T` doesn't implement `Copy`.
+        is_const_fn: bool,
+    },
 
     /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
     FieldSized {
index 1446f7dac36385c5f683ec43de579d79e98efb18..3bddf7fb6ffc4c9daa6d090a0db08418d13081eb 100644 (file)
@@ -119,9 +119,21 @@ pub fn extends(self, other: ty::ClosureKind) -> bool {
     /// See `Ty::to_opt_closure_kind` for more details.
     pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self {
-            ty::ClosureKind::Fn => tcx.types.i8,
-            ty::ClosureKind::FnMut => tcx.types.i16,
-            ty::ClosureKind::FnOnce => tcx.types.i32,
+            ClosureKind::Fn => tcx.types.i8,
+            ClosureKind::FnMut => tcx.types.i16,
+            ClosureKind::FnOnce => tcx.types.i32,
+        }
+    }
+
+    pub fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ClosureKind> {
+        if Some(def_id) == tcx.lang_items().fn_once_trait() {
+            Some(ClosureKind::FnOnce)
+        } else if Some(def_id) == tcx.lang_items().fn_mut_trait() {
+            Some(ClosureKind::FnMut)
+        } else if Some(def_id) == tcx.lang_items().fn_trait() {
+            Some(ClosureKind::Fn)
+        } else {
+            None
         }
     }
 }
index 57aec86785657c286e2771f102e90de6c7cc891c..72b597bb13d29caa22e322184925da867738a2d0 100644 (file)
@@ -198,7 +198,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
         let kind = match pat.kind {
             hir::PatKind::Wild => PatKind::Wild,
 
-            hir::PatKind::Lit(ref value) => self.lower_lit(value),
+            hir::PatKind::Lit(value) => self.lower_lit(value),
 
             hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
                 let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
index a970d180b1a9b377814b05009ecbbf4f4f1e2705..20d035fba195a7219e62568ae977841e9fc9d51f 100644 (file)
@@ -1919,17 +1919,13 @@ fn maybe_suggest_brackets_instead_of_braces(
         match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
             Ok(arr) => {
                 let hi = snapshot.prev_token.span;
-                self.struct_span_err(
-                    arr.span,
-                    "this code is interpreted as a block expression, not an array",
-                )
-                .multipart_suggestion(
-                    "try using [] instead of {}",
-                    vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
-                    Applicability::MaybeIncorrect,
-                )
-                .note("to define an array, one would use square brackets instead of curly braces")
-                .emit();
+                self.struct_span_err(arr.span, "this is a block expression, not an array")
+                    .multipart_suggestion(
+                        "to make an array, use square brackets instead of curly braces",
+                        vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
+                        Applicability::MaybeIncorrect,
+                    )
+                    .emit();
 
                 self.restore_snapshot(snapshot);
                 Some(self.mk_expr_err(arr.span))
index 48675fa88270adf3ec06b2f80a825c97138a213e..1f0a6e5ce9716263b3b7e67d9256b8a0b89030fd 100644 (file)
@@ -1061,7 +1061,6 @@ pub struct Resolver<'a> {
     /// and how the `impl Trait` fragments were introduced.
     invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext)>,
 
-    next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
     /// Some way to know that we are in a *trait* impl in `visit_assoc_item`.
     /// FIXME: Replace with a more general AST map (together with some other fields).
     trait_impl_items: FxHashSet<LocalDefId>,
@@ -1160,9 +1159,9 @@ fn parent(self, id: DefId) -> Option<DefId> {
 /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
 /// the resolver is no longer needed as all the relevant information is inline.
 impl ResolverAstLowering for Resolver<'_> {
-    fn def_key(&mut self, id: DefId) -> DefKey {
+    fn def_key(&self, id: DefId) -> DefKey {
         if let Some(id) = id.as_local() {
-            self.definitions().def_key(id)
+            self.definitions.def_key(id)
         } else {
             self.cstore().def_key(id)
         }
@@ -1189,24 +1188,20 @@ fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
         self.partial_res_map.get(&id).cloned()
     }
 
-    fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res>> {
+    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res>> {
         self.import_res_map.get(&id).cloned().unwrap_or_default()
     }
 
-    fn get_label_res(&mut self, id: NodeId) -> Option<NodeId> {
+    fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
         self.label_res_map.get(&id).cloned()
     }
 
-    fn definitions(&mut self) -> &mut Definitions {
-        &mut self.definitions
-    }
-
     fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
         StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
     }
 
-    fn lint_buffer(&mut self) -> &mut LintBuffer {
-        &mut self.lint_buffer
+    fn definitions(&self) -> &Definitions {
+        &self.definitions
     }
 
     fn next_node_id(&mut self) -> NodeId {
@@ -1249,16 +1244,7 @@ fn create_def(
             self.definitions.def_key(self.node_id_to_def_id[&node_id]),
         );
 
-        // Find the next free disambiguator for this key.
-        let next_disambiguator = &mut self.next_disambiguator;
-        let next_disambiguator = |parent, data| {
-            let next_disamb = next_disambiguator.entry((parent, data)).or_insert(0);
-            let disambiguator = *next_disamb;
-            *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
-            disambiguator
-        };
-
-        let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator, span);
+        let def_id = self.definitions.create_def(parent, data, expn_id, span);
 
         // Some things for which we allocate `LocalDefId`s don't correspond to
         // anything in the AST, so they don't have a `NodeId`. For these cases
@@ -1430,7 +1416,6 @@ pub fn new(
             def_id_to_node_id,
             placeholder_field_indices: Default::default(),
             invocation_parents,
-            next_disambiguator: Default::default(),
             trait_impl_items: Default::default(),
             legacy_const_generic_args: Default::default(),
             item_generics_num_lifetimes: Default::default(),
index 468c7a3c55b3626f39e5fc32a431ed45b7c93617..727847968e53a71034b5270b57579f84aba6bdeb 100644 (file)
@@ -2,10 +2,10 @@
 pub mod suggestions;
 
 use super::{
-    EvaluationResult, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
-    Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
-    OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
-    SelectionContext, SelectionError, TraitNotObjectSafe,
+    EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
+    MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
+    OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
+    PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
 };
 
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -21,6 +21,8 @@
 use rustc_hir::GenericParam;
 use rustc_hir::Item;
 use rustc_hir::Node;
+use rustc_infer::infer::error_reporting::same_type_modulo_infer;
+use rustc_infer::traits::TraitEngine;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::error::ExpectedFound;
@@ -103,6 +105,17 @@ fn report_arg_count_mismatch(
         found_args: Vec<ArgKind>,
         is_closure: bool,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+    /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
+    /// in that order, and returns the generic type corresponding to the
+    /// argument of that trait (corresponding to the closure arguments).
+    fn type_implements_fn_trait(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: ty::Binder<'tcx, Ty<'tcx>>,
+        constness: ty::BoundConstness,
+        polarity: ty::ImplPolarity,
+    ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
 }
 
 impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
@@ -563,7 +576,64 @@ fn report_selection_error(
                         }
 
                         // Try to report a help message
-                        if !trait_ref.has_infer_types_or_consts()
+                        if is_fn_trait
+                            && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
+                                obligation.param_env,
+                                trait_ref.self_ty(),
+                                trait_predicate.skip_binder().constness,
+                                trait_predicate.skip_binder().polarity,
+                            )
+                        {
+                            // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
+                            // suggestion to add trait bounds for the type, since we only typically implement
+                            // these traits once.
+
+                            // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
+                            // to implement.
+                            let selected_kind =
+                                ty::ClosureKind::from_def_id(self.tcx, trait_ref.def_id())
+                                    .expect("expected to map DefId to ClosureKind");
+                            if !implemented_kind.extends(selected_kind) {
+                                err.note(
+                                    &format!(
+                                        "`{}` implements `{}`, but it must implement `{}`, which is more general",
+                                        trait_ref.skip_binder().self_ty(),
+                                        implemented_kind,
+                                        selected_kind
+                                    )
+                                );
+                            }
+
+                            // Note any argument mismatches
+                            let given_ty = params.skip_binder();
+                            let expected_ty = trait_ref.skip_binder().substs.type_at(1);
+                            if let ty::Tuple(given) = given_ty.kind()
+                                && let ty::Tuple(expected) = expected_ty.kind()
+                            {
+                                if expected.len() != given.len() {
+                                    // Note number of types that were expected and given
+                                    err.note(
+                                        &format!(
+                                            "expected a closure taking {} argument{}, but one taking {} argument{} was given",
+                                            given.len(),
+                                            if given.len() == 1 { "" } else { "s" },
+                                            expected.len(),
+                                            if expected.len() == 1 { "" } else { "s" },
+                                        )
+                                    );
+                                } else if !same_type_modulo_infer(given_ty, expected_ty) {
+                                    // Print type mismatch
+                                    let (expected_args, given_args) =
+                                        self.cmp(given_ty, expected_ty);
+                                    err.note_expected_found(
+                                        &"a closure with arguments",
+                                        expected_args,
+                                        &"a closure with arguments",
+                                        given_args,
+                                    );
+                                }
+                            }
+                        } else if !trait_ref.has_infer_types_or_consts()
                             && self.predicate_can_apply(obligation.param_env, trait_ref)
                         {
                             // If a where-clause may be useful, remind the
@@ -1148,6 +1218,52 @@ fn report_arg_count_mismatch(
 
         err
     }
+
+    fn type_implements_fn_trait(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: ty::Binder<'tcx, Ty<'tcx>>,
+        constness: ty::BoundConstness,
+        polarity: ty::ImplPolarity,
+    ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
+        self.commit_if_ok(|_| {
+            for trait_def_id in [
+                self.tcx.lang_items().fn_trait(),
+                self.tcx.lang_items().fn_mut_trait(),
+                self.tcx.lang_items().fn_once_trait(),
+            ] {
+                let Some(trait_def_id) = trait_def_id else { continue };
+                // Make a fresh inference variable so we can determine what the substitutions
+                // of the trait are.
+                let var = self.next_ty_var(TypeVariableOrigin {
+                    span: DUMMY_SP,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                });
+                let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
+                let obligation = Obligation::new(
+                    ObligationCause::dummy(),
+                    param_env,
+                    ty.rebind(ty::TraitPredicate {
+                        trait_ref: ty::TraitRef::new(trait_def_id, substs),
+                        constness,
+                        polarity,
+                    })
+                    .to_predicate(self.tcx),
+                );
+                let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
+                fulfill_cx.register_predicate_obligation(self, obligation);
+                if fulfill_cx.select_all_or_error(self).is_empty() {
+                    return Ok((
+                        ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
+                            .expect("expected to map DefId to ClosureKind"),
+                        ty.rebind(self.resolve_vars_if_possible(var)),
+                    ));
+                }
+            }
+
+            Err(())
+        })
+    }
 }
 
 trait InferCtxtPrivExt<'hir, 'tcx> {
@@ -2285,10 +2401,10 @@ fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
     }
 }
 
-pub fn recursive_type_with_infinite_size_error(
-    tcx: TyCtxt<'_>,
+pub fn recursive_type_with_infinite_size_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
     type_def_id: DefId,
-    spans: Vec<Span>,
+    spans: Vec<(Span, Option<hir::HirId>)>,
 ) {
     assert!(type_def_id.is_local());
     let span = tcx.hir().span_if_local(type_def_id).unwrap();
@@ -2297,7 +2413,7 @@ pub fn recursive_type_with_infinite_size_error(
     let mut err =
         struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
     err.span_label(span, "recursive type has infinite size");
-    for &span in &spans {
+    for &(span, _) in &spans {
         err.span_label(span, "recursive without indirection");
     }
     let msg = format!(
@@ -2305,16 +2421,25 @@ pub fn recursive_type_with_infinite_size_error(
         path,
     );
     if spans.len() <= 4 {
+        // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
         err.multipart_suggestion(
             &msg,
             spans
-                .iter()
-                .flat_map(|&span| {
-                    [
-                        (span.shrink_to_lo(), "Box<".to_string()),
-                        (span.shrink_to_hi(), ">".to_string()),
-                    ]
-                    .into_iter()
+                .into_iter()
+                .flat_map(|(span, field_id)| {
+                    if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) {
+                        // If we match an `Option` and can grab the span of the Option's generic, then
+                        // suggest boxing the generic arg for a non-null niche optimization.
+                        vec![
+                            (generic_span.shrink_to_lo(), "Box<".to_string()),
+                            (generic_span.shrink_to_hi(), ">".to_string()),
+                        ]
+                    } else {
+                        vec![
+                            (span.shrink_to_lo(), "Box<".to_string()),
+                            (span.shrink_to_hi(), ">".to_string()),
+                        ]
+                    }
                 })
                 .collect(),
             Applicability::HasPlaceholders,
@@ -2325,6 +2450,34 @@ pub fn recursive_type_with_infinite_size_error(
     err.emit();
 }
 
+/// Extract the span for the generic type `T` of `Option<T>` in a field definition
+fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
+    let node = tcx.hir().find(field_id?);
+
+    // Expect a field from our field_id
+    let Some(hir::Node::Field(field_def)) = node
+        else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) };
+
+    // Match a type that is a simple QPath with no Self
+    let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind
+        else { return None };
+
+    // Check if the path we're checking resolves to Option
+    let hir::def::Res::Def(_, did) = path.res
+        else { return None };
+
+    // Bail if this path doesn't describe `::core::option::Option`
+    if !tcx.is_diagnostic_item(sym::Option, did) {
+        return None;
+    }
+
+    // Match a single generic arg in the 0th path segment
+    let generic_arg = path.segments.last()?.args?.args.get(0)?;
+
+    // Take the span out of the type, if it's a type
+    if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None }
+}
+
 /// Summarizes information
 #[derive(Clone)]
 pub enum ArgKind {
index 505d78d800a3a388a5db1e528a2e16e13ecc008d..58e002b3360818382bdc4363bf0d410fbbb8bc6b 100644 (file)
@@ -1988,7 +1988,7 @@ fn note_obligation_cause_code<T>(
             ObligationCauseCode::Coercion { source: _, target } => {
                 err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
             }
-            ObligationCauseCode::RepeatVec(is_const_fn) => {
+            ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
                 err.note(
                     "the `Copy` trait is required because the repeated element will be copied",
                 );
index b8f3efe6462ead3ebc863767033ab19b1611f031..7efc82efd15c30c60034df6da010b48acccdfdd2 100644 (file)
 pub enum Representability {
     Representable,
     ContainsRecursive,
-    SelfRecursive(Vec<Span>),
+    /// Return a list of types that are included in themselves:
+    /// the spans where they are self-included, and (if found)
+    /// the HirId of the FieldDef that defines the self-inclusion.
+    SelfRecursive(Vec<(Span, Option<hir::HirId>)>),
 }
 
 /// Check whether a type is representable. This means it cannot contain unboxed
 /// structural recursion. This check is needed for structs and enums.
-pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability {
+pub fn ty_is_representable<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
+) -> Representability {
     debug!("is_type_representable: {:?}", ty);
     // To avoid a stack overflow when checking an enum variant or struct that
     // contains a different, structurally recursive type, maintain a stack of
@@ -38,11 +46,12 @@ pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> R
     let mut force_result = false;
     let r = is_type_structurally_recursive(
         tcx,
-        sp,
         &mut seen,
         &mut shadow_seen,
         &mut representable_cache,
         ty,
+        sp,
+        field_id,
         &mut force_result,
     );
     debug!("is_type_representable: {:?} is {:?}", ty, r);
@@ -61,11 +70,12 @@ fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representabilit
 
 fn are_inner_types_recursive<'tcx>(
     tcx: TyCtxt<'tcx>,
-    sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
     shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
     force_result: &mut bool,
 ) -> Representability {
     debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
@@ -75,11 +85,12 @@ fn are_inner_types_recursive<'tcx>(
             fold_repr(fields.iter().map(|ty| {
                 is_type_structurally_recursive(
                     tcx,
-                    sp,
                     seen,
                     shadow_seen,
                     representable_cache,
                     ty,
+                    sp,
+                    field_id,
                     force_result,
                 )
             }))
@@ -88,20 +99,26 @@ fn are_inner_types_recursive<'tcx>(
         // FIXME(#11924) Behavior undecided for zero-length vectors.
         ty::Array(ty, _) => is_type_structurally_recursive(
             tcx,
-            sp,
             seen,
             shadow_seen,
             representable_cache,
             *ty,
+            sp,
+            field_id,
             force_result,
         ),
         ty::Adt(def, substs) => {
             // Find non representable fields with their spans
             fold_repr(def.all_fields().map(|field| {
                 let ty = field.ty(tcx, substs);
-                let span = match field.did.as_local().and_then(|id| tcx.hir().find_by_def_id(id)) {
-                    Some(hir::Node::Field(field)) => field.ty.span,
-                    _ => sp,
+                let (sp, field_id) = match field
+                    .did
+                    .as_local()
+                    .map(|id| tcx.hir().local_def_id_to_hir_id(id))
+                    .and_then(|id| tcx.hir().find(id))
+                {
+                    Some(hir::Node::Field(field)) => (field.ty.span, Some(field.hir_id)),
+                    _ => (sp, field_id),
                 };
 
                 let mut result = None;
@@ -130,7 +147,7 @@ fn are_inner_types_recursive<'tcx>(
                 // result without adjusting).
                 if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
                     *force_result = true;
-                    result = Some(Representability::SelfRecursive(vec![span]));
+                    result = Some(Representability::SelfRecursive(vec![(sp, field_id)]));
                 }
 
                 if result == None {
@@ -161,16 +178,17 @@ fn are_inner_types_recursive<'tcx>(
                         result = Some(
                             match is_type_structurally_recursive(
                                 tcx,
-                                span,
                                 &mut nested_seen,
                                 shadow_seen,
                                 representable_cache,
                                 raw_adt_ty,
+                                sp,
+                                field_id,
                                 force_result,
                             ) {
                                 Representability::SelfRecursive(_) => {
                                     if *force_result {
-                                        Representability::SelfRecursive(vec![span])
+                                        Representability::SelfRecursive(vec![(sp, field_id)])
                                     } else {
                                         Representability::ContainsRecursive
                                     }
@@ -208,15 +226,16 @@ fn are_inner_types_recursive<'tcx>(
                         result = Some(
                             match is_type_structurally_recursive(
                                 tcx,
-                                span,
                                 seen,
                                 shadow_seen,
                                 representable_cache,
                                 ty,
+                                sp,
+                                field_id,
                                 force_result,
                             ) {
                                 Representability::SelfRecursive(_) => {
-                                    Representability::SelfRecursive(vec![span])
+                                    Representability::SelfRecursive(vec![(sp, field_id)])
                                 }
                                 x => x,
                             },
@@ -247,29 +266,31 @@ fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
 // contain any types on stack `seen`?
 fn is_type_structurally_recursive<'tcx>(
     tcx: TyCtxt<'tcx>,
-    sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
     shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
     force_result: &mut bool,
 ) -> Representability {
-    debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
+    debug!("is_type_structurally_recursive: {:?} {:?} {:?}", ty, sp, field_id);
     if let Some(representability) = representable_cache.get(&ty) {
         debug!(
-            "is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
-            ty, sp, representability
+            "is_type_structurally_recursive: {:?} {:?} {:?} - (cached) {:?}",
+            ty, sp, field_id, representability
         );
         return representability.clone();
     }
 
     let representability = is_type_structurally_recursive_inner(
         tcx,
-        sp,
         seen,
         shadow_seen,
         representable_cache,
         ty,
+        sp,
+        field_id,
         force_result,
     );
 
@@ -279,11 +300,12 @@ fn is_type_structurally_recursive<'tcx>(
 
 fn is_type_structurally_recursive_inner<'tcx>(
     tcx: TyCtxt<'tcx>,
-    sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
     shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
     force_result: &mut bool,
 ) -> Representability {
     match ty.kind() {
@@ -305,7 +327,7 @@ fn is_type_structurally_recursive_inner<'tcx>(
                 if let Some(&seen_adt) = iter.next() {
                     if same_adt(seen_adt, *def) {
                         debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
-                        return Representability::SelfRecursive(vec![sp]);
+                        return Representability::SelfRecursive(vec![(sp, field_id)]);
                     }
                 }
 
@@ -335,11 +357,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
             shadow_seen.push(*def);
             let out = are_inner_types_recursive(
                 tcx,
-                sp,
                 seen,
                 shadow_seen,
                 representable_cache,
                 ty,
+                sp,
+                field_id,
                 force_result,
             );
             shadow_seen.pop();
@@ -350,11 +373,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
             // No need to push in other cases.
             are_inner_types_recursive(
                 tcx,
-                sp,
                 seen,
                 shadow_seen,
                 representable_cache,
                 ty,
+                sp,
+                field_id,
                 force_result,
             )
         }
index 5362ca8d719781e66c065a0c3196f93bf90b7b01..7cb478d78880acbea2f8d1dab399287d91aacb42 100644 (file)
@@ -1045,7 +1045,7 @@ pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalD
     // recursive type. It is only necessary to throw an error on those that
     // contain themselves. For case 2, there must be an inner type that will be
     // caught by case 1.
-    match representability::ty_is_representable(tcx, rty, sp) {
+    match representability::ty_is_representable(tcx, rty, sp, None) {
         Representability::SelfRecursive(spans) => {
             recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
             return false;
index d2b462b595960639d29957a30eb30c2f8223f57e..00bc16452b9b9e741c001de5a867b1bc4179ae13 100644 (file)
@@ -39,6 +39,7 @@ pub fn emit_coerce_suggestions(
         self.suggest_no_capture_closure(err, expected, expr_ty);
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
         self.suggest_missing_parentheses(err, expr);
+        self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
         self.report_closure_inferred_return_type(err, expected);
index 4d3fdea1fc373959e96c71496fd8f0129ff3689c..2a1b7a5ab47ba6f696adb1293813718acb549987 100644 (file)
@@ -774,57 +774,68 @@ pub(in super::super) fn check_block_with_expected(
         let prev_diverges = self.diverges.get();
         let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
 
-        let (ctxt, ()) =
-            self.with_breakable_ctxt(blk.hir_id, ctxt, || {
-                for (pos, s) in blk.stmts.iter().enumerate() {
-                    self.check_stmt(s, blk.stmts.len() - 1 == pos);
-                }
+        let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
+            for (pos, s) in blk.stmts.iter().enumerate() {
+                self.check_stmt(s, blk.stmts.len() - 1 == pos);
+            }
 
-                // check the tail expression **without** holding the
-                // `enclosing_breakables` lock below.
-                let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
-
-                let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-                let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
-                let coerce = ctxt.coerce.as_mut().unwrap();
-                if let Some(tail_expr_ty) = tail_expr_ty {
-                    let tail_expr = tail_expr.unwrap();
-                    let span = self.get_expr_coercion_span(tail_expr);
-                    let cause =
-                        self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
-                    coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
-                } else {
-                    // Subtle: if there is no explicit tail expression,
-                    // that is typically equivalent to a tail expression
-                    // of `()` -- except if the block diverges. In that
-                    // case, there is no value supplied from the tail
-                    // expression (assuming there are no other breaks,
-                    // this implies that the type of the block will be
-                    // `!`).
-                    //
-                    // #41425 -- label the implicit `()` as being the
-                    // "found type" here, rather than the "expected type".
-                    if !self.diverges.get().is_always() {
-                        // #50009 -- Do not point at the entire fn block span, point at the return type
-                        // span, as it is the cause of the requirement, and
-                        // `consider_hint_about_removing_semicolon` will point at the last expression
-                        // if it were a relevant part of the error. This improves usability in editors
-                        // that highlight errors inline.
-                        let mut sp = blk.span;
-                        let mut fn_span = None;
-                        if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
-                            let ret_sp = decl.output.span();
-                            if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
-                                // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
-                                // output would otherwise be incorrect and even misleading. Make sure
-                                // the span we're aiming at correspond to a `fn` body.
-                                if block_sp == blk.span {
-                                    sp = ret_sp;
-                                    fn_span = Some(ident.span);
-                                }
+            // check the tail expression **without** holding the
+            // `enclosing_breakables` lock below.
+            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
+
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
+            let coerce = ctxt.coerce.as_mut().unwrap();
+            if let Some(tail_expr_ty) = tail_expr_ty {
+                let tail_expr = tail_expr.unwrap();
+                let span = self.get_expr_coercion_span(tail_expr);
+                let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
+                let ty_for_diagnostic = coerce.merged_ty();
+                // We use coerce_inner here because we want to augment the error
+                // suggesting to wrap the block in square brackets if it might've
+                // been mistaken array syntax
+                coerce.coerce_inner(
+                    self,
+                    &cause,
+                    Some(tail_expr),
+                    tail_expr_ty,
+                    Some(&mut |diag: &mut Diagnostic| {
+                        self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic);
+                    }),
+                    false,
+                );
+            } else {
+                // Subtle: if there is no explicit tail expression,
+                // that is typically equivalent to a tail expression
+                // of `()` -- except if the block diverges. In that
+                // case, there is no value supplied from the tail
+                // expression (assuming there are no other breaks,
+                // this implies that the type of the block will be
+                // `!`).
+                //
+                // #41425 -- label the implicit `()` as being the
+                // "found type" here, rather than the "expected type".
+                if !self.diverges.get().is_always() {
+                    // #50009 -- Do not point at the entire fn block span, point at the return type
+                    // span, as it is the cause of the requirement, and
+                    // `consider_hint_about_removing_semicolon` will point at the last expression
+                    // if it were a relevant part of the error. This improves usability in editors
+                    // that highlight errors inline.
+                    let mut sp = blk.span;
+                    let mut fn_span = None;
+                    if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
+                        let ret_sp = decl.output.span();
+                        if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
+                            // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
+                            // output would otherwise be incorrect and even misleading. Make sure
+                            // the span we're aiming at correspond to a `fn` body.
+                            if block_sp == blk.span {
+                                sp = ret_sp;
+                                fn_span = Some(ident.span);
                             }
                         }
-                        coerce.coerce_forced_unit(
+                    }
+                    coerce.coerce_forced_unit(
                         self,
                         &self.misc(sp),
                         &mut |err| {
@@ -837,21 +848,25 @@ pub(in super::super) fn check_block_with_expected(
                                     // Our block must be a `assign desugar local; assignment`
                                     if let Some(hir::Node::Block(hir::Block {
                                         stmts:
-                                            [hir::Stmt {
-                                                kind:
-                                                    hir::StmtKind::Local(hir::Local {
-                                                        source: hir::LocalSource::AssignDesugar(_),
-                                                        ..
-                                                    }),
-                                                ..
-                                            }, hir::Stmt {
-                                                kind:
-                                                    hir::StmtKind::Expr(hir::Expr {
-                                                        kind: hir::ExprKind::Assign(..),
-                                                        ..
-                                                    }),
-                                                ..
-                                            }],
+                                            [
+                                                hir::Stmt {
+                                                    kind:
+                                                        hir::StmtKind::Local(hir::Local {
+                                                            source:
+                                                                hir::LocalSource::AssignDesugar(_),
+                                                            ..
+                                                        }),
+                                                    ..
+                                                },
+                                                hir::Stmt {
+                                                    kind:
+                                                        hir::StmtKind::Expr(hir::Expr {
+                                                            kind: hir::ExprKind::Assign(..),
+                                                            ..
+                                                        }),
+                                                    ..
+                                                },
+                                            ],
                                         ..
                                     })) = self.tcx.hir().find(blk.hir_id)
                                     {
@@ -871,9 +886,9 @@ pub(in super::super) fn check_block_with_expected(
                         },
                         false,
                     );
-                    }
                 }
-            });
+            }
+        });
 
         if ctxt.may_break {
             // If we can break from the block, then the block's exit is always reachable
index e6a98ad6dc051aa8ce3cf97584b60b28db604284..68d555b3a651d224a2dbb0f16592b916aed2d0b2 100644 (file)
@@ -766,6 +766,77 @@ pub(in super::super) fn suggest_missing_parentheses(
         }
     }
 
+    /// Given an expression type mismatch, peel any `&` expressions until we get to
+    /// a block expression, and then suggest replacing the braces with square braces
+    /// if it was possibly mistaken array syntax.
+    pub(crate) fn suggest_block_to_brackets_peeling_refs(
+        &self,
+        diag: &mut Diagnostic,
+        mut expr: &hir::Expr<'_>,
+        mut expr_ty: Ty<'tcx>,
+        mut expected_ty: Ty<'tcx>,
+    ) {
+        loop {
+            match (&expr.kind, expr_ty.kind(), expected_ty.kind()) {
+                (
+                    hir::ExprKind::AddrOf(_, _, inner_expr),
+                    ty::Ref(_, inner_expr_ty, _),
+                    ty::Ref(_, inner_expected_ty, _),
+                ) => {
+                    expr = *inner_expr;
+                    expr_ty = *inner_expr_ty;
+                    expected_ty = *inner_expected_ty;
+                }
+                (hir::ExprKind::Block(blk, _), _, _) => {
+                    self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty);
+                    break;
+                }
+                _ => break,
+            }
+        }
+    }
+
+    /// Suggest wrapping the block in square brackets instead of curly braces
+    /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
+    pub(crate) fn suggest_block_to_brackets(
+        &self,
+        diag: &mut Diagnostic,
+        blk: &hir::Block<'_>,
+        blk_ty: Ty<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) {
+        if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() {
+            if self.can_coerce(blk_ty, *elem_ty)
+                && blk.stmts.is_empty()
+                && blk.rules == hir::BlockCheckMode::DefaultBlock
+            {
+                let source_map = self.tcx.sess.source_map();
+                if let Ok(snippet) = source_map.span_to_snippet(blk.span) {
+                    if snippet.starts_with('{') && snippet.ends_with('}') {
+                        diag.multipart_suggestion_verbose(
+                            "to create an array, use square brackets instead of curly braces",
+                            vec![
+                                (
+                                    blk.span
+                                        .shrink_to_lo()
+                                        .with_hi(rustc_span::BytePos(blk.span.lo().0 + 1)),
+                                    "[".to_string(),
+                                ),
+                                (
+                                    blk.span
+                                        .shrink_to_hi()
+                                        .with_lo(rustc_span::BytePos(blk.span.hi().0 - 1)),
+                                    "]".to_string(),
+                                ),
+                            ],
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                }
+            }
+        }
+    }
+
     fn is_loop(&self, id: hir::HirId) -> bool {
         let node = self.tcx.hir().get(id);
         matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. }))
index b775f24f8efd85f506b0b10cb01e720d0716873e..e7cfa3a7c14939fde344f4f93b00856280f65730 100644 (file)
@@ -95,13 +95,6 @@ pub fn enter<F, R>(&mut self, f: F) -> R
         let def_id = self.def_id;
         self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
     }
-
-    /// WF-checking doesn't need to recompute opaque types and can instead use
-    /// the type_of query to get them from typeck.
-    pub fn reveal_defining_opaque_types(mut self) -> Self {
-        self.infcx = self.infcx.reveal_defining_opaque_types();
-        self
-    }
 }
 
 impl<'a, 'tcx> Inherited<'a, 'tcx> {
index 5b3aee7428829ea6259156a485f10c87372d3fe8..bd08da9529a5f89635ffa47d5a3b1cf74eedef7a 100644 (file)
@@ -968,7 +968,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<
 
 fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
     CheckWfFcxBuilder {
-        inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
+        inherited: Inherited::build(tcx, def_id),
         id: hir::HirId::make_owner(def_id),
         span,
         param_env: tcx.param_env(def_id),
index 6a7841d3de6af1b4c0b2db384513739412f4c91b..68d80022b4c80d9992110b8911a794cdd7f88c5f 100644 (file)
@@ -84,7 +84,7 @@
 //! have to change, and is it worse or better now? Would any patterns become truly inexpressible?
 //! Could we carve out special exceptions for those patterns? Should we?
 //!
-//! A secondary goal of this project is to see if we can disamiguate the many functions of
+//! A secondary goal of this project is to see if we can disambiguate the many functions of
 //! pointer<->integer casts enough for the definition of `usize` to be loosened so that it
 //! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue
 //! to conflate these notions). This would potentially make it possible to more efficiently
 //! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the
 //! following information:
 //!
-//! * The **address-space** it is part of (i.e. "data" vs "code" in WASM).
+//! * The **address-space** it is part of (e.g. "data" vs "code" in WASM).
 //! * The **address** it points to, which can be represented by a `usize`.
 //! * The **provenance** it has, defining the memory it has permission to access.
 //!
 //! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers,
 //! we would like to know why, and what needs to be done to fix it.)
 //!
-//! Something more complicated and just generally *evil* like a XOR-List requires more significant
+//! Something more complicated and just generally *evil* like an XOR-List requires more significant
 //! changes like allocating all nodes in a pre-allocated Vec or Arena and using a pointer
 //! to the whole allocation to reconstitute the XORed addresses.
 //!
 //! special attention at all, because they're generally accessing memory outside the scope of
 //! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile".
 //!
-//! Under [Strict Provenance] is is Undefined Behaviour to:
+//! Under [Strict Provenance] it is Undefined Behaviour to:
 //!
 //! * Access memory through a pointer that does not have provenance over that memory.
 //!
index a9edec80540dd1d375292c398c45bd9dd0d2605e..c11a35ab947a808160bd1051916664ee3c71b239 100644 (file)
 //! For reference, the `std` library requires `AtomicBool`s and pointer-sized atomics, although
 //! `core` does not.
 //!
-//! Currently you'll need to use `#[cfg(target_arch)]` primarily to
-//! conditionally compile in code with atomics. There is an unstable
-//! `#[cfg(target_has_atomic)]` as well which may be stabilized in the future.
+//! The `#[cfg(target_has_atomic)]` attribute can be used to conditionally
+//! compile based on the target's supported bit widths. It is a key-value
+//! option set for each supported size, with values "8", "16", "32", "64",
+//! "128", and "ptr" for pointer-sized atomics.
 //!
 //! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm
 //!
index 133ced5f26cfbdbf5df83d3cd011929503f925ee..819ec10a4b4b65c0caa682989a5054543d7b1f0d 100644 (file)
     feature(slice_index_methods, coerce_unsized, sgx_platform)
 )]
 #![deny(rustc::existing_doc_keyword)]
-// std is implemented with unstable features, many of which are internal
-// compiler details that will never be stable
-// NB: the following list is sorted to minimize merge conflicts.
+//
+// Language features:
 #![feature(alloc_error_handler)]
-#![feature(alloc_layout_extra)]
-#![feature(allocator_api)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
-#![feature(array_error_internals)]
-#![feature(assert_matches)]
 #![feature(associated_type_bounds)]
-#![feature(async_iterator)]
-#![feature(atomic_mut_ptr)]
-#![feature(bench_black_box)]
 #![feature(box_syntax)]
 #![feature(c_unwind)]
-#![feature(c_variadic)]
-#![feature(cfg_accessible)]
-#![feature(cfg_eval)]
 #![feature(cfg_target_thread_local)]
-#![feature(char_error_internals)]
-#![feature(char_internals)]
-#![feature(concat_bytes)]
 #![feature(concat_idents)]
 #![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
 #![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
-#![feature(const_format_args)]
-#![feature(const_io_structs)]
-#![feature(const_ip)]
-#![feature(const_ipv4)]
-#![feature(const_ipv6)]
 #![feature(const_mut_refs)]
-#![feature(const_option)]
-#![feature(const_socketaddr)]
 #![feature(const_trait_impl)]
-#![feature(c_size_t)]
-#![feature(core_ffi_c)]
-#![feature(core_intrinsics)]
-#![feature(core_panic)]
-#![feature(custom_test_frameworks)]
 #![feature(decl_macro)]
+#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
-#![feature(rustdoc_internals)]
-#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
-#![feature(duration_checked_float)]
-#![feature(duration_constants)]
-#![feature(edition_panic)]
-#![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
-#![feature(extend_one)]
-#![feature(float_minimum_maximum)]
-#![feature(format_args_nl)]
-#![feature(strict_provenance)]
-#![feature(get_mut_unchecked)]
-#![feature(hashmap_internals)]
-#![feature(int_error_internals)]
 #![feature(intra_doc_pointers)]
 #![feature(lang_items)]
 #![feature(linkage)]
-#![feature(log_syntax)]
-#![feature(map_try_insert)]
-#![feature(maybe_uninit_slice)]
-#![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
-#![feature(mixed_integer_ops)]
 #![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
 #![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(new_uninit)]
 #![feature(nll)]
+#![feature(platform_intrinsics)]
+#![feature(prelude_import)]
+#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
+#![feature(staged_api)]
+#![feature(thread_local)]
+#![feature(try_blocks)]
+//
+// Library features (core):
+#![feature(array_error_internals)]
+#![feature(atomic_mut_ptr)]
+#![feature(char_error_internals)]
+#![feature(char_internals)]
+#![feature(core_intrinsics)]
+#![feature(duration_checked_float)]
+#![feature(duration_constants)]
+#![feature(exact_size_is_empty)]
+#![feature(extend_one)]
+#![feature(float_minimum_maximum)]
+#![feature(hashmap_internals)]
+#![feature(int_error_internals)]
+#![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_write_slice)]
+#![feature(mixed_integer_ops)]
 #![feature(nonnull_slice_from_raw_parts)]
-#![feature(once_cell)]
+#![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
-#![feature(panic_can_unwind)]
-#![feature(panic_unwind)]
-#![feature(platform_intrinsics)]
 #![feature(portable_simd)]
-#![feature(prelude_import)]
 #![feature(ptr_as_uninit)]
 #![feature(raw_os_nonzero)]
-#![feature(rustc_attrs)]
-#![feature(saturating_int_impl)]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
-#![feature(staged_api)]
 #![feature(std_internals)]
-#![feature(stdsimd)]
 #![feature(str_internals)]
-#![feature(test)]
-#![feature(thread_local)]
-#![feature(thread_local_internals)]
-#![feature(toowned_clone_into)]
+#![feature(strict_provenance)]
 #![feature(total_cmp)]
-#![feature(trace_macros)]
-#![feature(try_blocks)]
+//
+// Library features (alloc):
+#![feature(alloc_layout_extra)]
+#![feature(allocator_api)]
+#![feature(get_mut_unchecked)]
+#![feature(map_try_insert)]
+#![feature(new_uninit)]
+#![feature(toowned_clone_into)]
 #![feature(try_reserve_kind)]
 #![feature(vec_into_raw_parts)]
-// NB: the above list is sorted to minimize merge conflicts.
+//
+// Library features (unwind):
+#![feature(panic_unwind)]
+//
+// Only for re-exporting:
+#![feature(assert_matches)]
+#![feature(async_iterator)]
+#![feature(c_size_t)]
+#![feature(c_variadic)]
+#![feature(cfg_accessible)]
+#![feature(cfg_eval)]
+#![feature(concat_bytes)]
+#![feature(const_format_args)]
+#![feature(core_ffi_c)]
+#![feature(core_panic)]
+#![feature(custom_test_frameworks)]
+#![feature(edition_panic)]
+#![feature(format_args_nl)]
+#![feature(log_syntax)]
+#![feature(once_cell)]
+#![feature(saturating_int_impl)]
+#![feature(stdsimd)]
+#![feature(test)]
+#![feature(trace_macros)]
+//
+// Only used in tests/benchmarks:
+#![feature(bench_black_box)]
+//
+// Only for const-ness:
+#![feature(const_io_structs)]
+#![feature(const_ip)]
+#![feature(const_ipv4)]
+#![feature(const_ipv6)]
+#![feature(const_option)]
+#![feature(const_socketaddr)]
+#![feature(thread_local_internals)]
+//
 #![default_lib_allocator]
 
 // Explicitly import the prelude. The compiler uses this same unstable attribute
index 81c05509c4e804ede8348ea273de54c6e7691f82..7698c2de24d5c8d9e3b21b6c2d02a07aec0b1252 100644 (file)
@@ -1,5 +1,6 @@
 use std::cell::RefCell;
 use std::default::Default;
+use std::fmt;
 use std::hash::Hash;
 use std::iter;
 use std::lazy::SyncOnceCell as OnceCell;
@@ -355,7 +356,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
 /// Anything with a source location and set of attributes and, optionally, a
 /// name. That is, anything that can be documented. This doesn't correspond
 /// directly to the AST's concept of an item; it's a strict superset.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 crate struct Item {
     /// The name of this item.
     /// Optional because not every item has a name, e.g. impls.
@@ -370,6 +371,27 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
     crate cfg: Option<Arc<Cfg>>,
 }
 
+/// NOTE: this does NOT unconditionally print every item, to avoid thousands of lines of logs.
+/// If you want to see the debug output for attributes and the `kind` as well, use `{:#?}` instead of `{:?}`.
+impl fmt::Debug for Item {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let alternate = f.alternate();
+        // hand-picked fields that don't bloat the logs too much
+        let mut fmt = f.debug_struct("Item");
+        fmt.field("name", &self.name)
+            .field("visibility", &self.visibility)
+            .field("def_id", &self.def_id);
+        // allow printing the full item if someone really wants to
+        if alternate {
+            fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
+        } else {
+            fmt.field("kind", &self.type_());
+            fmt.field("docs", &self.doc_value());
+        }
+        fmt.finish()
+    }
+}
+
 // `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Item, 56);
index f8c9dca566b93975278849a26b0279f401ccf64d..46901bd3b9b349b378b0e0c164d8d87e0d534d9b 100644 (file)
@@ -104,6 +104,17 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:71:1
    |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─allocN─╼ ff ff ff 7f                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:74:1
+   |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
    |
@@ -113,7 +124,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:74:1
+  --> $DIR/ub-wide-ptr.rs:77:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation)
@@ -124,7 +135,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:77:1
+  --> $DIR/ub-wide-ptr.rs:80:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -135,7 +146,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:81:1
+  --> $DIR/ub-wide-ptr.rs:84:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean
@@ -146,29 +157,29 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:87:1
+  --> $DIR/ub-wide-ptr.rs:90:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾allocN─╼                                     │ ╾──╼
+               ╾allocN─╼                                     │ ╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:93:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾allocN─╼                                     │ ╾──╼
+               ╾allocN─╼                                     │ ╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:97:1
+  --> $DIR/ub-wide-ptr.rs:100:1
    |
 LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
 LL | |
@@ -183,7 +194,7 @@ LL | | };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:105:1
+  --> $DIR/ub-wide-ptr.rs:108:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@@ -194,7 +205,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:108:1
+  --> $DIR/ub-wide-ptr.rs:111:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@@ -205,7 +216,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:111:1
+  --> $DIR/ub-wide-ptr.rs:114:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
@@ -216,7 +227,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:113:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer
@@ -227,7 +238,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:115:1
+  --> $DIR/ub-wide-ptr.rs:118:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -238,7 +249,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:117:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -249,7 +260,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:119:1
+  --> $DIR/ub-wide-ptr.rs:122:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -260,7 +271,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:123:1
+  --> $DIR/ub-wide-ptr.rs:126:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@@ -271,7 +282,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:127:1
+  --> $DIR/ub-wide-ptr.rs:130:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer
@@ -282,7 +293,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:129:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
@@ -293,17 +304,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
            }
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:135:5
+  --> $DIR/ub-wide-ptr.rs:138:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:139:5
+  --> $DIR/ub-wide-ptr.rs:142:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 12 bytes starting at offset N is out-of-bounds
 
-error: aborting due to 28 previous errors
+error: aborting due to 29 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index ded007ce2813979b39d47cf5674c39998867cbbe..b76f88928678ae8ffffdd1ffd40e8479c6314e9a 100644 (file)
@@ -104,6 +104,17 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:71:1
    |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────allocN───────╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:74:1
+   |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
    |
@@ -113,7 +124,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:74:1
+  --> $DIR/ub-wide-ptr.rs:77:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation)
@@ -124,7 +135,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:77:1
+  --> $DIR/ub-wide-ptr.rs:80:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -135,7 +146,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:81:1
+  --> $DIR/ub-wide-ptr.rs:84:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean
@@ -146,29 +157,29 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:87:1
+  --> $DIR/ub-wide-ptr.rs:90:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾──────allocN───────╼                         │ ╾──────╼
+               ╾──────allocN───────╼                         │ ╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:93:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾──────allocN───────╼                         │ ╾──────╼
+               ╾──────allocN───────╼                         │ ╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:97:1
+  --> $DIR/ub-wide-ptr.rs:100:1
    |
 LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
 LL | |
@@ -183,7 +194,7 @@ LL | | };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:105:1
+  --> $DIR/ub-wide-ptr.rs:108:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@@ -194,7 +205,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:108:1
+  --> $DIR/ub-wide-ptr.rs:111:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@@ -205,7 +216,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:111:1
+  --> $DIR/ub-wide-ptr.rs:114:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
@@ -216,7 +227,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:113:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer
@@ -227,7 +238,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:115:1
+  --> $DIR/ub-wide-ptr.rs:118:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -238,7 +249,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:117:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -249,7 +260,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:119:1
+  --> $DIR/ub-wide-ptr.rs:122:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -260,7 +271,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:123:1
+  --> $DIR/ub-wide-ptr.rs:126:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@@ -271,7 +282,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:127:1
+  --> $DIR/ub-wide-ptr.rs:130:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer
@@ -282,7 +293,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:129:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
@@ -293,17 +304,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
            }
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:135:5
+  --> $DIR/ub-wide-ptr.rs:138:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:139:5
+  --> $DIR/ub-wide-ptr.rs:142:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 24 bytes starting at offset N is out-of-bounds
 
-error: aborting due to 28 previous errors
+error: aborting due to 29 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index 0fb9f7960ce1a4871f5b911d68c929203634e9f0..ea48a095df95c53ab7f61a134147c80c63aa7ee9 100644 (file)
@@ -67,6 +67,9 @@ impl Trait for bool {}
 // bad slice: length too big
 const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
 //~^ ERROR it is undefined behavior to use this value
+// bad slice: length computation overflows
+const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+//~^ ERROR it is undefined behavior to use this value
 // bad slice: length not an int
 const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
 //~^ ERROR it is undefined behavior to use this value
index 5c0d7d94d64f1bf061f4e5ca3e0c22309e957c32..5a78313c483504849499f4a03719aab3a4b14011 100644 (file)
@@ -2,8 +2,9 @@
 
 #![feature(const_size_of_val, const_align_of_val)]
 #![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)]
+#![feature(const_slice_from_raw_parts)]
 
-use std::mem;
+use std::{mem, ptr};
 
 struct Foo(u32);
 
@@ -34,6 +35,8 @@ union Ugh {
 const SIZE_OF_SLICE: usize = mem::size_of_val("foobar".as_bytes());
 
 const SIZE_OF_DANGLING: usize = unsafe { mem::size_of_val_raw(0x100 as *const i32) };
+const SIZE_OF_BIG: usize =
+    unsafe { mem::size_of_val_raw(ptr::slice_from_raw_parts(0 as *const u8, isize::MAX as usize)) };
 const ALIGN_OF_DANGLING: usize = unsafe { mem::align_of_val_raw(0x100 as *const i16) };
 
 fn main() {
@@ -46,6 +49,7 @@ fn main() {
     assert_eq!(ALIGN_OF_UGH, mem::align_of::<Ugh>());
 
     assert_eq!(SIZE_OF_DANGLING, mem::size_of::<i32>());
+    assert_eq!(SIZE_OF_BIG, isize::MAX as usize);
     assert_eq!(ALIGN_OF_DANGLING, mem::align_of::<i16>());
 
     assert_eq!(SIZE_OF_SLICE, "foobar".len());
diff --git a/src/test/ui/did_you_mean/brackets-to-braces-single-element.rs b/src/test/ui/did_you_mean/brackets-to-braces-single-element.rs
new file mode 100644 (file)
index 0000000..4d01097
--- /dev/null
@@ -0,0 +1,10 @@
+const A: [&str; 1] = { "hello" };
+//~^ ERROR mismatched types
+
+const B: &[u32] = &{ 1 };
+//~^ ERROR mismatched types
+
+const C: &&[u32; 1] = &&{ 1 };
+//~^ ERROR mismatched types
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr b/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr
new file mode 100644 (file)
index 0000000..6ded03e
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0308]: mismatched types
+  --> $DIR/brackets-to-braces-single-element.rs:1:24
+   |
+LL | const A: [&str; 1] = { "hello" };
+   |                        ^^^^^^^ expected array `[&'static str; 1]`, found `&str`
+   |
+help: to create an array, use square brackets instead of curly braces
+   |
+LL | const A: [&str; 1] = [ "hello" ];
+   |                      ~         ~
+
+error[E0308]: mismatched types
+  --> $DIR/brackets-to-braces-single-element.rs:4:19
+   |
+LL | const B: &[u32] = &{ 1 };
+   |                   ^^^^^^ expected slice `[u32]`, found integer
+   |
+   = note: expected reference `&'static [u32]`
+              found reference `&{integer}`
+help: to create an array, use square brackets instead of curly braces
+   |
+LL | const B: &[u32] = &[ 1 ];
+   |                    ~   ~
+
+error[E0308]: mismatched types
+  --> $DIR/brackets-to-braces-single-element.rs:7:27
+   |
+LL | const C: &&[u32; 1] = &&{ 1 };
+   |                           ^ expected array `[u32; 1]`, found integer
+   |
+help: to create an array, use square brackets instead of curly braces
+   |
+LL | const C: &&[u32; 1] = &&[ 1 ];
+   |                         ~   ~
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 53dad85900a65ae1b478e5efc421c8fa4813ede2..070ffaa1eff00fb2bc0116b39df25924ca49070a 100644 (file)
@@ -1,15 +1,16 @@
 fn main() {}
 
-const FOO: [u8; 3] = { //~ ERROR this code is interpreted as a block expression
+const FOO: [u8; 3] = {
+    //~^ ERROR this is a block expression, not an array
     1, 2, 3
 };
 
 const BAR: [&str; 3] = {"one", "two", "three"};
-//~^ ERROR this code is interpreted as a block expression
+//~^ ERROR this is a block expression, not an array
 
 fn foo() {
     {1, 2, 3};
-    //~^ ERROR this code is interpreted as a block expression
+    //~^ ERROR this is a block expression, not an array
 }
 
 fn bar() {
index 9ab491f5c238f03f39266198fcb04c4614a8c315..d5ad1a72b8250444ba5cd6a9a7e97b38af8584fd 100644 (file)
@@ -1,46 +1,45 @@
-error: this code is interpreted as a block expression, not an array
+error: this is a block expression, not an array
   --> $DIR/issue-87830-try-brackets-for-arrays.rs:3:22
    |
 LL |   const FOO: [u8; 3] = {
    |  ______________________^
+LL | |
 LL | |     1, 2, 3
 LL | | };
    | |_^
    |
-   = note: to define an array, one would use square brackets instead of curly braces
-help: try using [] instead of {}
+help: to make an array, use square brackets instead of curly braces
    |
 LL ~ const FOO: [u8; 3] = [
+LL |
 LL |     1, 2, 3
 LL ~ ];
    |
 
-error: this code is interpreted as a block expression, not an array
-  --> $DIR/issue-87830-try-brackets-for-arrays.rs:7:24
+error: this is a block expression, not an array
+  --> $DIR/issue-87830-try-brackets-for-arrays.rs:8:24
    |
 LL | const BAR: [&str; 3] = {"one", "two", "three"};
    |                        ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: to define an array, one would use square brackets instead of curly braces
-help: try using [] instead of {}
+help: to make an array, use square brackets instead of curly braces
    |
 LL | const BAR: [&str; 3] = ["one", "two", "three"];
    |                        ~                     ~
 
-error: this code is interpreted as a block expression, not an array
-  --> $DIR/issue-87830-try-brackets-for-arrays.rs:11:5
+error: this is a block expression, not an array
+  --> $DIR/issue-87830-try-brackets-for-arrays.rs:12:5
    |
 LL |     {1, 2, 3};
    |     ^^^^^^^^^
    |
-   = note: to define an array, one would use square brackets instead of curly braces
-help: try using [] instead of {}
+help: to make an array, use square brackets instead of curly braces
    |
 LL |     [1, 2, 3];
    |     ~       ~
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
-  --> $DIR/issue-87830-try-brackets-for-arrays.rs:16:6
+  --> $DIR/issue-87830-try-brackets-for-arrays.rs:17:6
    |
 LL |     1, 2, 3
    |      ^ expected one of `.`, `;`, `?`, `}`, or an operator
index b110734642177fd39d6a371e9f5a63915fb3b350..066bf431a83d78e4ae21581ee887296f120b6eab 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: expected a `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F`
 LL |         call(f, ());
    |         ^^^^ expected an `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F`
    |
+   = note: expected a closure with arguments `((),)`
+              found a closure with arguments `(<_ as ATC<'a>>::Type,)`
 note: required by a bound in `call`
   --> $DIR/issue-62529-3.rs:9:36
    |
index 4d739a3823b1073246f1f42a344383617ac3ccb5..db32eb952ba79796caa6b7fdac16eb13d004536b 100644 (file)
@@ -8,8 +8,8 @@ LL | struct Foo { foo: Option<Option<Foo>> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo { foo: Box<Option<Option<Foo>>> }
-   |                   ++++                   +
+LL | struct Foo { foo: Option<Box<Option<Foo>>> }
+   |                          ++++           +
 
 error: aborting due to previous error
 
index e53134c5238c60ababa8bf516e91cee79777b99c..d23fd1474ac12fe497ea1dd217fadefd9a092811 100644 (file)
@@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
    |
-LL | struct Baz { q: Box<Option<Foo>> }
-   |                 ++++           +
+LL | struct Baz { q: Option<Box<Foo>> }
+   |                        ++++   +
 
 error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/issue-17431-2.rs:4:1
@@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo { q: Box<Option<Baz>> }
-   |                 ++++           +
+LL | struct Foo { q: Option<Box<Baz>> }
+   |                        ++++   +
 
 error: aborting due to 2 previous errors
 
index f5aeeec7337115dda48d2dc678b9ec36d523febe..ddf669b8fd1cb6733773b069185e7a1b0ec73dcc 100644 (file)
@@ -8,8 +8,8 @@ LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T>
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo<T> { foo: Box<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
-   |                      ++++                      +
+LL | struct Foo<T> { foo: Option<Box<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
+   |                             ++++              +
 
 error: aborting due to previous error
 
index aeaadaa69175e2a84b46c7a0c66fe1e1330344ea..6f8a7e3867b099eb6987f52bc1137f8881f475b3 100644 (file)
@@ -8,8 +8,8 @@ LL | enum Foo { Voo(Option<Option<Foo>>) }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | enum Foo { Voo(Box<Option<Option<Foo>>>) }
-   |                ++++                   +
+LL | enum Foo { Voo(Option<Box<Option<Foo>>>) }
+   |                       ++++           +
 
 error: aborting due to previous error
 
index 6a21472848a74d9345947f6aece40b350b4cda70..e853d0f8c8932d98ff5bd743ca95385264edffd4 100644 (file)
@@ -9,8 +9,8 @@ LL |     element: Option<S>
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable
    |
-LL |     element: Box<Option<S>>
-   |              ++++         +
+LL |     element: Option<Box<S>>
+   |                     ++++ +
 
 error: aborting due to previous error
 
index a9284535e4dc4221a6c1faf198fc113706f2ec5c..8b542bb69de2ed1e7dadc06f28f3685c424f2796 100644 (file)
@@ -7,6 +7,8 @@ LL |     let t8 = t8n(t7, t7p(f, g));
    |              required by a bound introduced by this call
    |
    = help: the trait `Fn<(_,)>` is not implemented for `impl Fn(((_, _), _))`
+   = note: expected a closure with arguments `(((_, _), _),)`
+              found a closure with arguments `(_,)`
 note: required by a bound in `t8n`
   --> $DIR/issue-59494.rs:5:45
    |
index 0726b16a91948d0afbeffe413bb630f55bca1067..536510814c57ca7f8ea2705653cff351d92ace7c 100644 (file)
@@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
    |
-LL | struct Baz { q: Box<Option<Foo>> }
-   |                 ++++           +
+LL | struct Baz { q: Option<Box<Foo>> }
+   |                        ++++   +
 
 error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/sized-cycle-note.rs:11:1
@@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo { q: Box<Option<Baz>> }
-   |                 ++++           +
+LL | struct Foo { q: Option<Box<Baz>> }
+   |                        ++++   +
 
 error: aborting due to 2 previous errors
 
index 98e92751360cfc0296e14b482ff70ee840265202..882ed577cf36626d00bf63a6fb55d23c2f3c2f6b 100644 (file)
@@ -9,8 +9,8 @@ LL |     tail: Option<ListNode>,
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
    |
-LL |     tail: Box<Option<ListNode>>,
-   |           ++++                +
+LL |     tail: Option<Box<ListNode>>,
+   |                  ++++        +
 
 error: aborting due to previous error
 
index cb71a55b09eaf29cd70e4657e51fb1d7fe525521..acfc60b51f330892710429c476ccfbc1ba26f27e 100644 (file)
@@ -12,8 +12,8 @@ LL | | }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
    |
-LL |     tail: Box<Option<ListNode>>,
-   |           ++++                +
+LL |     tail: Option<Box<ListNode>>,
+   |                  ++++        +
 
 error: aborting due to previous error
 
index c6d2434e424b10fc8871aacf63fa4174730757da..80a494f3f65eb20d83ecf57aa34b381a456f5ed3 100644 (file)
@@ -37,8 +37,8 @@ LL |     y: Option<Option<D<T>>>,
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable
    |
-LL |     y: Box<Option<Option<D<T>>>>,
-   |        ++++                    +
+LL |     y: Option<Box<Option<D<T>>>>,
+   |               ++++            +
 
 error[E0072]: recursive type `D` has infinite size
   --> $DIR/mutual-struct-recursion.rs:18:1
@@ -51,8 +51,8 @@ LL |     z: Option<Option<C<T>>>,
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable
    |
-LL |     z: Box<Option<Option<C<T>>>>,
-   |        ++++                    +
+LL |     z: Option<Box<Option<C<T>>>>,
+   |               ++++            +
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/trait-bounds/mismatch-fn-trait.rs b/src/test/ui/trait-bounds/mismatch-fn-trait.rs
new file mode 100644 (file)
index 0000000..0ed6404
--- /dev/null
@@ -0,0 +1,28 @@
+fn take(_f: impl FnMut(i32)) {}
+
+fn test1(f: impl FnMut(u32)) {
+    take(f)
+    //~^ ERROR [E0277]
+}
+
+fn test2(f: impl FnMut(i32, i32)) {
+    take(f)
+    //~^ ERROR [E0277]
+}
+
+fn test3(f: impl FnMut()) {
+    take(f)
+    //~^ ERROR [E0277]
+}
+
+fn test4(f: impl FnOnce(i32)) {
+    take(f)
+    //~^ ERROR [E0277]
+}
+
+fn test5(f: impl FnOnce(u32)) {
+    take(f)
+    //~^ ERROR [E0277]
+}
+
+fn main() {}
diff --git a/src/test/ui/trait-bounds/mismatch-fn-trait.stderr b/src/test/ui/trait-bounds/mismatch-fn-trait.stderr
new file mode 100644 (file)
index 0000000..961e6d8
--- /dev/null
@@ -0,0 +1,81 @@
+error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut(u32)`
+  --> $DIR/mismatch-fn-trait.rs:4:10
+   |
+LL |     take(f)
+   |     ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut(u32)`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected a closure with arguments `(u32,)`
+              found a closure with arguments `(i32,)`
+note: required by a bound in `take`
+  --> $DIR/mismatch-fn-trait.rs:1:18
+   |
+LL | fn take(_f: impl FnMut(i32)) {}
+   |                  ^^^^^^^^^^ required by this bound in `take`
+
+error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut(i32, i32)`
+  --> $DIR/mismatch-fn-trait.rs:9:10
+   |
+LL |     take(f)
+   |     ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut(i32, i32)`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected a closure taking 2 arguments, but one taking 1 argument was given
+note: required by a bound in `take`
+  --> $DIR/mismatch-fn-trait.rs:1:18
+   |
+LL | fn take(_f: impl FnMut(i32)) {}
+   |                  ^^^^^^^^^^ required by this bound in `take`
+
+error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut()`
+  --> $DIR/mismatch-fn-trait.rs:14:10
+   |
+LL |     take(f)
+   |     ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected a closure taking 0 arguments, but one taking 1 argument was given
+note: required by a bound in `take`
+  --> $DIR/mismatch-fn-trait.rs:1:18
+   |
+LL | fn take(_f: impl FnMut(i32)) {}
+   |                  ^^^^^^^^^^ required by this bound in `take`
+
+error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnOnce(i32)`
+  --> $DIR/mismatch-fn-trait.rs:19:10
+   |
+LL |     take(f)
+   |     ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnOnce(i32)`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: `impl FnOnce(i32)` implements `FnOnce`, but it must implement `FnMut`, which is more general
+note: required by a bound in `take`
+  --> $DIR/mismatch-fn-trait.rs:1:18
+   |
+LL | fn take(_f: impl FnMut(i32)) {}
+   |                  ^^^^^^^^^^ required by this bound in `take`
+
+error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnOnce(u32)`
+  --> $DIR/mismatch-fn-trait.rs:24:10
+   |
+LL |     take(f)
+   |     ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnOnce(u32)`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: `impl FnOnce(u32)` implements `FnOnce`, but it must implement `FnMut`, which is more general
+   = note: expected a closure with arguments `(u32,)`
+              found a closure with arguments `(i32,)`
+note: required by a bound in `take`
+  --> $DIR/mismatch-fn-trait.rs:1:18
+   |
+LL | fn take(_f: impl FnMut(i32)) {}
+   |                  ^^^^^^^^^^ required by this bound in `take`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type/type-recursive-box-shadowed.rs b/src/test/ui/type/type-recursive-box-shadowed.rs
new file mode 100644 (file)
index 0000000..e141c21
--- /dev/null
@@ -0,0 +1,12 @@
+//FIXME(compiler-errors): This fixup should suggest the full box path, not just `Box`
+
+struct Box<T> {
+    t: T,
+}
+
+struct Foo {
+    //~^ ERROR recursive type `Foo` has infinite size
+    inner: Foo,
+}
+
+fn main() {}
diff --git a/src/test/ui/type/type-recursive-box-shadowed.stderr b/src/test/ui/type/type-recursive-box-shadowed.stderr
new file mode 100644 (file)
index 0000000..c22d848
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `Foo` has infinite size
+  --> $DIR/type-recursive-box-shadowed.rs:7:1
+   |
+LL | struct Foo {
+   | ^^^^^^^^^^ recursive type has infinite size
+LL |
+LL |     inner: Foo,
+   |            --- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
+   |
+LL |     inner: Box<Foo>,
+   |            ++++   +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
index 8558f761ee8f5006358ecda43efcad2e764a839d..e8084f0d0826af0b18b2d0ebaf513c31a59c3175 100644 (file)
@@ -1,6 +1,30 @@
 struct T1 { //~ ERROR E0072
     foo: isize,
-    foolish: T1
+    foolish: T1,
+}
+
+struct T2 { //~ ERROR E0072
+    inner: Option<T2>,
+}
+
+type OptionT3 = Option<T3>;
+
+struct T3 { //~ ERROR E0072
+    inner: OptionT3,
+}
+
+struct T4(Option<T4>); //~ ERROR E0072
+
+enum T5 { //~ ERROR E0072
+    Variant(Option<T5>),
+}
+
+enum T6 { //~ ERROR E0072
+    Variant{ field: Option<T6> },
+}
+
+struct T7 { //~ ERROR E0072
+    foo: std::cell::Cell<Option<T7>>,
 }
 
 fn main() { }
index 5a94a0fd6831a43eb37a204bd7bb09468de08a99..04392f7390dfc3fd52cbc764c46909f62116111b 100644 (file)
@@ -4,14 +4,93 @@ error[E0072]: recursive type `T1` has infinite size
 LL | struct T1 {
    | ^^^^^^^^^ recursive type has infinite size
 LL |     foo: isize,
-LL |     foolish: T1
+LL |     foolish: T1,
    |              -- recursive without indirection
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable
    |
-LL |     foolish: Box<T1>
+LL |     foolish: Box<T1>,
    |              ++++  +
 
-error: aborting due to previous error
+error[E0072]: recursive type `T2` has infinite size
+  --> $DIR/type-recursive.rs:6:1
+   |
+LL | struct T2 {
+   | ^^^^^^^^^ recursive type has infinite size
+LL |     inner: Option<T2>,
+   |            ---------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T2` representable
+   |
+LL |     inner: Option<Box<T2>>,
+   |                   ++++  +
+
+error[E0072]: recursive type `T3` has infinite size
+  --> $DIR/type-recursive.rs:12:1
+   |
+LL | struct T3 {
+   | ^^^^^^^^^ recursive type has infinite size
+LL |     inner: OptionT3,
+   |            -------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T3` representable
+   |
+LL |     inner: Box<OptionT3>,
+   |            ++++        +
+
+error[E0072]: recursive type `T4` has infinite size
+  --> $DIR/type-recursive.rs:16:1
+   |
+LL | struct T4(Option<T4>);
+   | ^^^^^^^^^^----------^^
+   | |         |
+   | |         recursive without indirection
+   | recursive type has infinite size
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T4` representable
+   |
+LL | struct T4(Option<Box<T4>>);
+   |                  ++++  +
+
+error[E0072]: recursive type `T5` has infinite size
+  --> $DIR/type-recursive.rs:18:1
+   |
+LL | enum T5 {
+   | ^^^^^^^ recursive type has infinite size
+LL |     Variant(Option<T5>),
+   |             ---------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T5` representable
+   |
+LL |     Variant(Option<Box<T5>>),
+   |                    ++++  +
+
+error[E0072]: recursive type `T6` has infinite size
+  --> $DIR/type-recursive.rs:22:1
+   |
+LL | enum T6 {
+   | ^^^^^^^ recursive type has infinite size
+LL |     Variant{ field: Option<T6> },
+   |                     ---------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T6` representable
+   |
+LL |     Variant{ field: Option<Box<T6>> },
+   |                            ++++  +
+
+error[E0072]: recursive type `T7` has infinite size
+  --> $DIR/type-recursive.rs:26:1
+   |
+LL | struct T7 {
+   | ^^^^^^^^^ recursive type has infinite size
+LL |     foo: std::cell::Cell<Option<T7>>,
+   |          --------------------------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T7` representable
+   |
+LL |     foo: Box<std::cell::Cell<Option<T7>>>,
+   |          ++++                           +
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0072`.
index f379d73eecff723c39044f9af0424cfd86525ee6..0ea1c1dcd5bde0c73bcd183398029e0ae87dd30a 100644 (file)
@@ -7,6 +7,7 @@ LL |     let x = call_it(&S, 22);
    |             required by a bound introduced by this call
    |
    = help: the trait `Fn<(isize,)>` is not implemented for `S`
+   = note: `S` implements `FnMut`, but it must implement `Fn`, which is more general
 note: required by a bound in `call_it`
   --> $DIR/unboxed-closures-fnmut-as-fn.rs:22:14
    |