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
}
}
-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),
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;
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;
/// 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>,
}
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;
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;
}
}
+#[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,
) -> &'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)]
}
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);
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() {
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();
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
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);
}
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))
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(
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;
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)))
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)))
}
) -> 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.
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 `{}`",
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)
.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(
#[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>,
Definitions {
table,
+ next_disambiguator: Default::default(),
expansions_that_defined: Default::default(),
def_id_to_span,
stable_crate_id,
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);
// 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 },
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(),
/// 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
/// 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,
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> {
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 }
}
}
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
}
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),
}
});
+ 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>,
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));
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);
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()
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 {
/// 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
}
}
}
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());
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))
/// 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>,
/// 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)
}
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 {
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
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(),
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};
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;
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> {
}
// 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
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> {
}
}
-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();
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!(
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,
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 {
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",
);
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
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);
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);
fold_repr(fields.iter().map(|ty| {
is_type_structurally_recursive(
tcx,
- sp,
seen,
shadow_seen,
representable_cache,
ty,
+ sp,
+ field_id,
force_result,
)
}))
// 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;
// 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 {
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
}
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,
},
// 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,
);
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() {
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)]);
}
}
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();
// No need to push in other cases.
are_inner_types_recursive(
tcx,
- sp,
seen,
shadow_seen,
representable_cache,
ty,
+ sp,
+ field_id,
force_result,
)
}
// 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;
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);
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| {
// 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)
{
},
false,
);
- }
}
- });
+ }
+ });
if ctxt.may_break {
// If we can break from the block, then the block's exit is always reachable
}
}
+ /// 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(..), .. }))
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> {
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),
//! 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.
//!
//! 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
//!
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
use std::cell::RefCell;
use std::default::Default;
+use std::fmt;
use std::hash::Hash;
use std::iter;
use std::lazy::SyncOnceCell as OnceCell;
/// 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.
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);
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
|
}
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)
}
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
}
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
}
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 | |
}
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
}
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
}
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
}
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
}
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)
}
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)
}
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)
}
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
}
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
}
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
}
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`.
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
|
}
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)
}
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
}
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
}
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 | |
}
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
}
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
}
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
}
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
}
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)
}
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)
}
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)
}
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
}
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
}
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
}
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`.
// 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
#![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);
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() {
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());
--- /dev/null
+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() {}
--- /dev/null
+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`.
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() {
-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
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
|
|
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
|
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
|
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
|
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
|
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
|
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
| 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
|
|
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
|
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
|
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
|
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
|
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
|
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
--- /dev/null
+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() {}
--- /dev/null
+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`.
--- /dev/null
+//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() {}
--- /dev/null
+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`.
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() { }
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`.
| 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
|