Skip to content

Commit 37c945d

Browse files
committed
Auto merge of #70204 - Centril:unshackled-lowering, r=Zoxc
Liberate `rustc_ast_lowering` from `rustc` The whole point of this PR is the very last commit, in which we remove `rustc` as one of `rustc_ast_lowering`'s dependencies, thereby improving `./x.py` parallelism and working towards #65031. Noteworthy: - From `rustc::arena` we move logic into `arena`, in particular `declare_arena!`. This is then used in `rustc_ast_lowering` so that lowering has its own separate arena. - Some linting code is unfortunately moved to `rustc_session::lint` cause its used both in `rustc_lint` and `rustc_ast_lowering`, and this is their common dependency. - `rustc_session::CrateDisambiguator` is moved into `rustc_ast` so that `rustc::hir::map::definitions` can be moved into `rustc_hir`, so that `rustc_ast_lowering` can stop referring to `rustc::hir`. r? @Zoxc
2 parents e4b01c7 + 40cec78 commit 37c945d

File tree

27 files changed

+384
-375
lines changed

27 files changed

+384
-375
lines changed

Cargo.lock

+2-1
Original file line numberDiff line numberDiff line change
@@ -3477,8 +3477,8 @@ dependencies = [
34773477
name = "rustc_ast_lowering"
34783478
version = "0.0.0"
34793479
dependencies = [
3480+
"arena",
34803481
"log",
3481-
"rustc",
34823482
"rustc_ast",
34833483
"rustc_ast_pretty",
34843484
"rustc_data_structures",
@@ -3725,6 +3725,7 @@ name = "rustc_hir"
37253725
version = "0.0.0"
37263726
dependencies = [
37273727
"lazy_static 1.4.0",
3728+
"log",
37283729
"rustc_ast",
37293730
"rustc_ast_pretty",
37303731
"rustc_data_structures",

src/libarena/lib.rs

+182
Original file line numberDiff line numberDiff line change
@@ -488,5 +488,187 @@ impl DroplessArena {
488488
}
489489
}
490490

491+
/// Calls the destructor for an object when dropped.
492+
struct DropType {
493+
drop_fn: unsafe fn(*mut u8),
494+
obj: *mut u8,
495+
}
496+
497+
unsafe fn drop_for_type<T>(to_drop: *mut u8) {
498+
std::ptr::drop_in_place(to_drop as *mut T)
499+
}
500+
501+
impl Drop for DropType {
502+
fn drop(&mut self) {
503+
unsafe { (self.drop_fn)(self.obj) }
504+
}
505+
}
506+
507+
/// An arena which can be used to allocate any type.
508+
/// Allocating in this arena is unsafe since the type system
509+
/// doesn't know which types it contains. In order to
510+
/// allocate safely, you must store a PhantomData<T>
511+
/// alongside this arena for each type T you allocate.
512+
#[derive(Default)]
513+
pub struct DropArena {
514+
/// A list of destructors to run when the arena drops.
515+
/// Ordered so `destructors` gets dropped before the arena
516+
/// since its destructor can reference memory in the arena.
517+
destructors: RefCell<Vec<DropType>>,
518+
arena: DroplessArena,
519+
}
520+
521+
impl DropArena {
522+
#[inline]
523+
pub unsafe fn alloc<T>(&self, object: T) -> &mut T {
524+
let mem =
525+
self.arena.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut _ as *mut T;
526+
// Write into uninitialized memory.
527+
ptr::write(mem, object);
528+
let result = &mut *mem;
529+
// Record the destructor after doing the allocation as that may panic
530+
// and would cause `object`'s destuctor to run twice if it was recorded before
531+
self.destructors
532+
.borrow_mut()
533+
.push(DropType { drop_fn: drop_for_type::<T>, obj: result as *mut T as *mut u8 });
534+
result
535+
}
536+
537+
#[inline]
538+
pub unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
539+
let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
540+
if vec.is_empty() {
541+
return &mut [];
542+
}
543+
let len = vec.len();
544+
545+
let start_ptr = self
546+
.arena
547+
.alloc_raw(len.checked_mul(mem::size_of::<T>()).unwrap(), mem::align_of::<T>())
548+
as *mut _ as *mut T;
549+
550+
let mut destructors = self.destructors.borrow_mut();
551+
// Reserve space for the destructors so we can't panic while adding them
552+
destructors.reserve(len);
553+
554+
// Move the content to the arena by copying it and then forgetting
555+
// the content of the SmallVec
556+
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
557+
mem::forget(vec.drain(..));
558+
559+
// Record the destructors after doing the allocation as that may panic
560+
// and would cause `object`'s destuctor to run twice if it was recorded before
561+
for i in 0..len {
562+
destructors.push(DropType {
563+
drop_fn: drop_for_type::<T>,
564+
obj: start_ptr.offset(i as isize) as *mut u8,
565+
});
566+
}
567+
568+
slice::from_raw_parts_mut(start_ptr, len)
569+
}
570+
}
571+
572+
#[macro_export]
573+
macro_rules! arena_for_type {
574+
([][$ty:ty]) => {
575+
$crate::TypedArena<$ty>
576+
};
577+
([few $(, $attrs:ident)*][$ty:ty]) => {
578+
::std::marker::PhantomData<$ty>
579+
};
580+
([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
581+
$crate::arena_for_type!([$($attrs),*]$args)
582+
};
583+
}
584+
585+
#[macro_export]
586+
macro_rules! which_arena_for_type {
587+
([][$arena:expr]) => {
588+
::std::option::Option::Some($arena)
589+
};
590+
([few$(, $attrs:ident)*][$arena:expr]) => {
591+
::std::option::Option::None
592+
};
593+
([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
594+
$crate::which_arena_for_type!([$($attrs),*]$args)
595+
};
596+
}
597+
598+
#[macro_export]
599+
macro_rules! declare_arena {
600+
([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
601+
#[derive(Default)]
602+
pub struct Arena<$tcx> {
603+
pub dropless: $crate::DroplessArena,
604+
drop: $crate::DropArena,
605+
$($name: $crate::arena_for_type!($a[$ty]),)*
606+
}
607+
608+
#[marker]
609+
pub trait ArenaAllocatable {}
610+
611+
impl<T: Copy> ArenaAllocatable for T {}
612+
613+
unsafe trait ArenaField<'tcx>: Sized {
614+
/// Returns a specific arena to allocate from.
615+
/// If `None` is returned, the `DropArena` will be used.
616+
fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>>;
617+
}
618+
619+
unsafe impl<'tcx, T> ArenaField<'tcx> for T {
620+
#[inline]
621+
default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>> {
622+
panic!()
623+
}
624+
}
625+
626+
$(
627+
#[allow(unused_lifetimes)]
628+
impl<$tcx> ArenaAllocatable for $ty {}
629+
unsafe impl<$tcx> ArenaField<$tcx> for $ty {
630+
#[inline]
631+
fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena<Self>> {
632+
$crate::which_arena_for_type!($a[&_arena.$name])
633+
}
634+
}
635+
)*
636+
637+
impl<'tcx> Arena<'tcx> {
638+
#[inline]
639+
pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T {
640+
if !::std::mem::needs_drop::<T>() {
641+
return self.dropless.alloc(value);
642+
}
643+
match <T as ArenaField<'tcx>>::arena(self) {
644+
::std::option::Option::Some(arena) => arena.alloc(value),
645+
::std::option::Option::None => unsafe { self.drop.alloc(value) },
646+
}
647+
}
648+
649+
#[inline]
650+
pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
651+
if value.is_empty() {
652+
return &mut [];
653+
}
654+
self.dropless.alloc_slice(value)
655+
}
656+
657+
pub fn alloc_from_iter<'a, T: ArenaAllocatable>(
658+
&'a self,
659+
iter: impl ::std::iter::IntoIterator<Item = T>,
660+
) -> &'a mut [T] {
661+
if !::std::mem::needs_drop::<T>() {
662+
return self.dropless.alloc_from_iter(iter);
663+
}
664+
match <T as ArenaField<'tcx>>::arena(self) {
665+
::std::option::Option::Some(arena) => arena.alloc_from_iter(iter),
666+
::std::option::Option::None => unsafe { self.drop.alloc_from_iter(iter) },
667+
}
668+
}
669+
}
670+
}
671+
}
672+
491673
#[cfg(test)]
492674
mod tests;

0 commit comments

Comments
 (0)