Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce an arena type which may be used to allocate a list of types with destructors #59536

Merged
merged 6 commits into from
Apr 12, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/librustc/arena.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use arena::{TypedArena, DroplessArena};
use std::mem;

#[macro_export]
macro_rules! arena_types {
($macro:path, $args:tt, $tcx:lifetime) => (
$macro!($args, [
[] vtable_method: Option<(
rustc::hir::def_id::DefId,
rustc::ty::subst::SubstsRef<$tcx>
)>,
[decode] specialization_graph: rustc::traits::specialization_graph::Graph,
], $tcx);
Copy link
Contributor Author

@Zoxc Zoxc Mar 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list of types are declared here with a macro.

)
}

macro_rules! declare_arena {
([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
#[derive(Default)]
pub struct Arena<$tcx> {
dropless: DroplessArena,
$($name: TypedArena<$ty>,)*
}
}
}

macro_rules! impl_arena_allocatable {
([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
$(
impl ArenaAllocatable for $ty {}
impl<$tcx> ArenaField<$tcx> for $ty {
#[inline]
fn arena<'a>(arena: &'a Arena<$tcx>) -> &'a TypedArena<Self> {
&arena.$name
}
}
)*
}
}

arena_types!(declare_arena, [], 'tcx);

arena_types!(impl_arena_allocatable, [], 'tcx);

pub trait ArenaAllocatable {}

impl<T: Copy> ArenaAllocatable for T {}

pub trait ArenaField<'tcx>: Sized {
/// Returns a specific arena to allocate from.
fn arena<'a>(arena: &'a Arena<'tcx>) -> &'a TypedArena<Self>;
}

impl<'tcx, T> ArenaField<'tcx> for T {
#[inline]
default fn arena<'a>(_: &'a Arena<'tcx>) -> &'a TypedArena<Self> {
panic!()
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This impl can conflict with the types in the list :(

error[E0119]: conflicting implementations of trait `arena::ArenaAllocatable<'_>` for type `std::collections::HashSet<hir::item_local_id_inner::ItemLocalId, std::hash::BuildHasherDefault<rustc_data_structures::fx::FxHasher>>`:
  --> src\librustc\arena.rs:42:13
   |
4  |  / macro_rules! arena_types {
5  |  |     ($macro:path, $args:tt, $tcx:lifetime) => (
6  |  |         $macro!($args, [
   |  |_________-
7  | ||             [] vtable_method: Option<(
8  | ||                 rustc::hir::def_id::DefId,
9  | ||                 rustc::ty::subst::SubstsRef<$tcx>
...  ||
15 | ||             [] item_local_set: rustc::util::nodemap::ItemLocalSet,
16 | ||         ], $tcx);
   | ||_________________- in this macro invocation
17 |  |     )
18 |  | }
   |  |_- in this expansion of `arena_types!`
...
37 | /  macro_rules! impl_arena_allocatable {
38 | |      ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
39 | |          $(
40 | |              impl_specialized_decodable!($a $ty, $tcx);
41 | |
42 | |              impl<$tcx> ArenaAllocatable<$tcx> for $ty {
   | |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::collections::HashSet<hir::item_local_id_inner::ItemLocalId, std::hash::BuildHasherDefault<rustc_data_structures::fx::FxHasher>>`
...  |
49 | |      }
50 | |  }
   | |__- in this expansion of `impl_arena_allocatable!`
...
54 |    arena_types!(impl_arena_allocatable, [], 'tcx);
   |    ----------------------------------------------- in this macro invocation
...
62 |    impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T {
   |    ------------------------------------------------ first implementation here
   |
   = note: upstream crates may add new impl of trait `std::marker::Copy` for type `std::collections::HashSet<hir::item_local_id_inner::ItemLocalId, std::hash::BuildHasherDefault<rustc_data_structures::fx::FxHasher>>` in future versions

error: aborting due to previous error

Do we have some way to express an ArenaAllocatable or Copy bound?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, it would be nice to be able to rely on sets and maps never being Copy...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a way around this using a marker trait.

}

impl<'tcx> Arena<'tcx> {
#[inline]
pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T {
if mem::needs_drop::<T>() {
<T as ArenaField<'tcx>>::arena(self).alloc(value)
} else {
self.dropless.alloc(value)
}
}

pub fn alloc_from_iter<
T: ArenaAllocatable,
I: IntoIterator<Item = T>
>(
&self,
iter: I
) -> &mut [T] {
if mem::needs_drop::<T>() {
<T as ArenaField<'tcx>>::arena(self).alloc_from_iter(iter)
} else {
self.dropless.alloc_from_iter(iter)
}
}
}
3 changes: 3 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#![cfg_attr(windows, feature(libc))]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(overlapping_marker_traits)]
#![feature(extern_types)]
#![feature(nll)]
#![feature(non_exhaustive)]
Expand Down Expand Up @@ -103,6 +104,8 @@ pub mod diagnostics;
#[macro_use]
pub mod query;

#[macro_use]
pub mod arena;
pub mod cfg;
pub mod dep_graph;
pub mod hir;
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ rustc_queries! {

Other {
query vtable_methods(key: ty::PolyTraitRef<'tcx>)
-> Lrc<Vec<Option<(DefId, SubstsRef<'tcx>)>>> {
-> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
no_force
desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
}
Expand All @@ -539,8 +539,7 @@ rustc_queries! {
query trait_impls_of(key: DefId) -> Lrc<ty::trait_def::TraitImpls> {
desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) }
}
query specialization_graph_of(_: DefId)
-> Lrc<specialization_graph::Graph> {}
query specialization_graph_of(_: DefId) -> &'tcx specialization_graph::Graph {}
query is_object_safe(key: DefId) -> bool {
desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
}
Expand Down
7 changes: 3 additions & 4 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use crate::infer::{InferCtxt, SuppressRegionErrors};
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::middle::region;
use crate::mir::interpret::ErrorHandled;
use rustc_data_structures::sync::Lrc;
use rustc_macros::HashStable;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
Expand Down Expand Up @@ -984,11 +983,11 @@ fn substitute_normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
fn vtable_methods<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>)
-> Lrc<Vec<Option<(DefId, SubstsRef<'tcx>)>>>
-> &'tcx [Option<(DefId, SubstsRef<'tcx>)>]
{
debug!("vtable_methods({:?})", trait_ref);

Lrc::new(
tcx.arena.alloc_from_iter(
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
let trait_methods = tcx.associated_items(trait_ref.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Method);
Expand Down Expand Up @@ -1039,7 +1038,7 @@ fn vtable_methods<'a, 'tcx>(

Some((def_id, substs))
})
}).collect()
})
)
}

Expand Down
5 changes: 2 additions & 3 deletions src/librustc/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use crate::infer::{InferCtxt, InferOk};
use crate::lint;
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use syntax_pos::DUMMY_SP;
use crate::traits::select::IntercrateAmbiguityCause;
use crate::ty::{self, TyCtxt, TypeFoldable};
Expand Down Expand Up @@ -289,7 +288,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
pub(super) fn specialization_graph_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_id: DefId,
) -> Lrc<specialization_graph::Graph> {
) -> &'tcx specialization_graph::Graph {
let mut sg = specialization_graph::Graph::new();

let mut trait_impls = tcx.all_impls(trait_id);
Expand Down Expand Up @@ -383,7 +382,7 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(
}
}

Lrc::new(sg)
tcx.arena.alloc(sg)
}

/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
Expand Down
13 changes: 6 additions & 7 deletions src/librustc/traits/specialize/specialization_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
use crate::traits;
use crate::ty::{self, TyCtxt, TypeFoldable};
use crate::ty::fast_reject::{self, SimplifiedType};
use rustc_data_structures::sync::Lrc;
use syntax::ast::Ident;
use crate::util::captures::Captures;
use crate::util::nodemap::{DefIdMap, FxHashMap};
Expand Down Expand Up @@ -439,13 +438,13 @@ impl<'a, 'gcx, 'tcx> Node {
}
}

pub struct Ancestors {
pub struct Ancestors<'tcx> {
trait_def_id: DefId,
specialization_graph: Lrc<Graph>,
specialization_graph: &'tcx Graph,
current_source: Option<Node>,
}

impl Iterator for Ancestors {
impl Iterator for Ancestors<'_> {
type Item = Node;
fn next(&mut self) -> Option<Node> {
let cur = self.current_source.take();
Expand Down Expand Up @@ -476,7 +475,7 @@ impl<T> NodeItem<T> {
}
}

impl<'a, 'gcx, 'tcx> Ancestors {
impl<'a, 'gcx, 'tcx> Ancestors<'gcx> {
/// Search the items from the given ancestors, returning each definition
/// with the given name and the given kind.
// FIXME(#35870): avoid closures being unexported due to `impl Trait`.
Expand Down Expand Up @@ -509,10 +508,10 @@ impl<'a, 'gcx, 'tcx> Ancestors {

/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors(tcx: TyCtxt<'_, '_, '_>,
pub fn ancestors(tcx: TyCtxt<'_, 'tcx, '_>,
trait_def_id: DefId,
start_from_impl: DefId)
-> Ancestors {
-> Ancestors<'tcx> {
let specialization_graph = tcx.specialization_graph_of(trait_def_id);
Ancestors {
trait_def_id,
Expand Down
52 changes: 52 additions & 0 deletions src/librustc/ty/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// The functionality in here is shared between persisting to crate metadata and
// persisting to incr. comp. caches.

use crate::arena::ArenaAllocatable;
use crate::hir::def_id::{DefId, CrateNum};
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use rustc_data_structures::fx::FxHashMap;
Expand Down Expand Up @@ -130,6 +131,26 @@ pub trait TyDecoder<'a, 'tcx: 'a>: Decoder {
}
}

#[inline]
pub fn decode_arena_allocable<'a, 'tcx, D, T: ArenaAllocatable + Decodable>(
decoder: &mut D
) -> Result<&'tcx T, D::Error>
where D: TyDecoder<'a, 'tcx>,
'tcx: 'a,
{
Ok(decoder.tcx().arena.alloc(Decodable::decode(decoder)?))
}

#[inline]
pub fn decode_arena_allocable_slice<'a, 'tcx, D, T: ArenaAllocatable + Decodable>(
decoder: &mut D
) -> Result<&'tcx [T], D::Error>
where D: TyDecoder<'a, 'tcx>,
'tcx: 'a,
{
Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable>::decode(decoder)?))
}

#[inline]
pub fn decode_cnum<'a, 'tcx, D>(decoder: &mut D) -> Result<CrateNum, D::Error>
where D: TyDecoder<'a, 'tcx>,
Expand Down Expand Up @@ -273,6 +294,35 @@ macro_rules! __impl_decoder_methods {
}
}

#[macro_export]
macro_rules! impl_arena_allocatable_decoder {
([$DecoderName:ident [$($typaram:tt),*]], [[decode] $name:ident: $ty:ty], $tcx:lifetime) => {
impl<$($typaram),*> SpecializedDecoder<&$tcx $ty> for $DecoderName<$($typaram),*> {
#[inline]
fn specialized_decode(&mut self) -> Result<&$tcx $ty, Self::Error> {
decode_arena_allocable(self)
}
}

impl<$($typaram),*> SpecializedDecoder<&$tcx [$ty]> for $DecoderName<$($typaram),*> {
#[inline]
fn specialized_decode(&mut self) -> Result<&$tcx [$ty], Self::Error> {
decode_arena_allocable_slice(self)
}
}
};
([$DecoderName:ident [$($typaram:tt),*]], [[] $name:ident: $ty:ty], $tcx:lifetime) => {};
}

#[macro_export]
macro_rules! impl_arena_allocatable_decoders {
($args:tt, [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
$(
impl_arena_allocatable_decoder!($args, [$a $name: $ty], $tcx);
)*
}
}

#[macro_export]
macro_rules! implement_ty_decoder {
($DecoderName:ident <$($typaram:tt),*>) => {
Expand Down Expand Up @@ -322,6 +372,8 @@ macro_rules! implement_ty_decoder {
// the caller to pick any lifetime for 'tcx, including 'static,
// by using the unspecialized proxies to them.

arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx);

impl<$($typaram),*> SpecializedDecoder<CrateNum>
for $DecoderName<$($typaram),*> {
fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Type context book-keeping.

use crate::arena::Arena;
use crate::dep_graph::DepGraph;
use crate::dep_graph::{self, DepNode, DepConstructor};
use crate::session::Session;
Expand Down Expand Up @@ -1003,6 +1004,7 @@ impl<'gcx> Deref for TyCtxt<'_, 'gcx, '_> {
}

pub struct GlobalCtxt<'tcx> {
pub arena: WorkerLocal<Arena<'tcx>>,
global_arenas: &'tcx WorkerLocal<GlobalArenas<'tcx>>,
global_interners: CtxtInterners<'tcx>,

Expand Down Expand Up @@ -1262,6 +1264,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
GlobalCtxt {
sess: s,
cstore,
arena: WorkerLocal::new(|_| Arena::default()),
global_arenas: &arenas.global,
global_interners: interners,
dep_graph,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/trait_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {

pub fn ancestors(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
of_impl: DefId)
-> specialization_graph::Ancestors {
-> specialization_graph::Ancestors<'gcx> {
specialization_graph::ancestors(tcx, self.def_id, of_impl)
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_mir/interpret/traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use rustc_data_structures::sync::Lrc;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{Size, Align, LayoutOf};
use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
Expand Down Expand Up @@ -35,7 +34,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>

self.tcx.vtable_methods(trait_ref)
} else {
Lrc::new(Vec::new())
&[]
};

let layout = self.layout_of(ty)?;
Expand Down
3 changes: 2 additions & 1 deletion src/libserialize/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,4 +911,5 @@ impl<T: UseSpecializedDecodable> Decodable for T {
impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {}
impl<T: ?Sized + Encodable> UseSpecializedEncodable for Box<T> {}
impl<T: Decodable> UseSpecializedDecodable for Box<T> {}

impl<'a, T: ?Sized + Decodable> UseSpecializedDecodable for &'a T {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see, ?Sized + Decodable is just Decodable, because Decodable: Sized (as it returns by-value) so the ?Sized does nothing.

impl<'a, T: ?Sized + Decodable> UseSpecializedDecodable for &'a [T] {}
Zoxc marked this conversation as resolved.
Show resolved Hide resolved