Skip to content

Commit

Permalink
Auto merge of rust-lang#91033 - JohnTitor:rollup-sr9zg6o, r=JohnTitor
Browse files Browse the repository at this point in the history
Rollup of 8 pull requests

Successful merges:

 - rust-lang#89258 (Make char conversion functions unstably const)
 - rust-lang#90578 (add const generics test)
 - rust-lang#90633 (Refactor single variant `Candidate` enum into a struct)
 - rust-lang#90800 (bootstap: create .cargo/config only if not present)
 - rust-lang#90942 (windows: Return the "Not Found" error when a path is empty)
 - rust-lang#90947 (Move some tests to more reasonable directories - 9.5)
 - rust-lang#90961 (Suggest removal of arguments for unit variant, not replacement)
 - rust-lang#90990 (Arenas cleanup)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Nov 19, 2021
2 parents ce3f3a5 + 1576a7c commit e8423e6
Show file tree
Hide file tree
Showing 153 changed files with 331 additions and 407 deletions.
25 changes: 17 additions & 8 deletions compiler/rustc_arena/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl<T> Default for TypedArena<T> {
// alloc() will trigger a grow().
ptr: Cell::new(ptr::null_mut()),
end: Cell::new(ptr::null_mut()),
chunks: RefCell::new(vec![]),
chunks: Default::default(),
_own: PhantomData,
}
}
Expand Down Expand Up @@ -325,13 +325,17 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {

unsafe impl<T: Send> Send for TypedArena<T> {}

/// An arena that can hold objects of multiple different types that impl `Copy`
/// and/or satisfy `!mem::needs_drop`.
pub struct DroplessArena {
/// A pointer to the start of the free space.
start: Cell<*mut u8>,

/// A pointer to the end of free space.
///
/// The allocation proceeds from the end of the chunk towards the start.
/// The allocation proceeds downwards from the end of the chunk towards the
/// start. (This is slightly simpler and faster than allocating upwards,
/// see <https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html>.)
/// When this pointer crosses the start pointer, a new chunk is allocated.
end: Cell<*mut u8>,

Expand Down Expand Up @@ -516,10 +520,14 @@ impl DroplessArena {
}
}

// Declare an `Arena` containing one dropless arena and many typed arenas (the
// types of the typed arenas are specified by the arguments). The dropless
// arena will be used for any types that impl `Copy`, and also for any of the
// specified types that satisfy `!mem::needs_drop`.
#[rustc_macro_transparency = "semitransparent"]
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
#[derive(Default)]
pub struct Arena<$tcx> {
pub struct Arena<'tcx> {
pub dropless: $crate::DroplessArena,
$($name: $crate::TypedArena<$ty>,)*
}
Expand All @@ -532,6 +540,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
) -> &'a mut [Self];
}

// Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
#[inline]
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
Expand All @@ -544,12 +553,11 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
) -> &'a mut [Self] {
arena.dropless.alloc_from_iter(iter)
}

}
$(
impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty {
#[inline]
fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
if !::std::mem::needs_drop::<Self>() {
arena.dropless.alloc(self)
} else {
Expand All @@ -559,7 +567,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {

#[inline]
fn allocate_from_iter<'a>(
arena: &'a Arena<$tcx>,
arena: &'a Arena<'tcx>,
iter: impl ::std::iter::IntoIterator<Item = Self>,
) -> &'a mut [Self] {
if !::std::mem::needs_drop::<Self>() {
Expand All @@ -577,6 +585,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
value.allocate_on(self)
}

// Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`.
#[inline]
pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
if value.is_empty() {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ mod item;
mod pat;
mod path;

rustc_hir::arena_types!(rustc_arena::declare_arena, 'tcx);
rustc_hir::arena_types!(rustc_arena::declare_arena);

struct LoweringContext<'a, 'hir: 'a> {
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
Expand Down
183 changes: 82 additions & 101 deletions compiler/rustc_const_eval/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,8 @@ impl TempState {
/// returned value in a promoted MIR, unless it's a subset
/// of a larger candidate.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Candidate {
/// Borrow of a constant temporary, candidate for lifetime extension.
Ref(Location),
}

impl Candidate {
fn source_info(&self, body: &Body<'_>) -> SourceInfo {
match self {
Candidate::Ref(location) => *body.source_info(*location),
}
}
pub struct Candidate {
location: Location,
}

struct Collector<'a, 'tcx> {
Expand Down Expand Up @@ -167,7 +158,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {

match *rvalue {
Rvalue::Ref(..) => {
self.candidates.push(Candidate::Ref(location));
self.candidates.push(Candidate { location });
}
_ => {}
}
Expand Down Expand Up @@ -209,36 +200,33 @@ struct Unpromotable;

impl<'tcx> Validator<'_, 'tcx> {
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
match candidate {
Candidate::Ref(loc) => {
let statement = &self.body[loc.block].statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
// We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway).
self.validate_local(place.local)?;

// The reference operation itself must be promotable.
// (Needs to come after `validate_local` to avoid ICEs.)
self.validate_ref(*kind, place)?;

// We do not check all the projections (they do not get promoted anyway),
// but we do stay away from promoting anything involving a dereference.
if place.projection.contains(&ProjectionElem::Deref) {
return Err(Unpromotable);
}
let loc = candidate.location;
let statement = &self.body[loc.block].statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
// We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway).
self.validate_local(place.local)?;

// The reference operation itself must be promotable.
// (Needs to come after `validate_local` to avoid ICEs.)
self.validate_ref(*kind, place)?;

// We cannot promote things that need dropping, since the promoted value
// would not get dropped.
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}
// We do not check all the projections (they do not get promoted anyway),
// but we do stay away from promoting anything involving a dereference.
if place.projection.contains(&ProjectionElem::Deref) {
return Err(Unpromotable);
}

Ok(())
}
_ => bug!(),
// We cannot promote things that need dropping, since the promoted value
// would not get dropped.
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}

Ok(())
}
_ => bug!(),
}
}

Expand Down Expand Up @@ -871,58 +859,55 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
}))
};
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
match candidate {
Candidate::Ref(loc) => {
let statement = &mut blocks[loc.block].statements[loc.statement_index];
match statement.kind {
StatementKind::Assign(box (
_,
Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
)) => {
// Use the underlying local for this (necessarily interior) borrow.
let ty = local_decls.local_decls()[place.local].ty;
let span = statement.source_info.span;

let ref_ty = tcx.mk_ref(
tcx.lifetimes.re_erased,
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
);

*region = tcx.lifetimes.re_erased;

let mut projection = vec![PlaceElem::Deref];
projection.extend(place.projection);
place.projection = tcx.intern_place_elems(&projection);

// Create a temp to hold the promoted reference.
// This is because `*r` requires `r` to be a local,
// otherwise we would use the `promoted` directly.
let mut promoted_ref = LocalDecl::new(ref_ty, span);
promoted_ref.source_info = statement.source_info;
let promoted_ref = local_decls.push(promoted_ref);
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);

let promoted_ref_statement = Statement {
source_info: statement.source_info,
kind: StatementKind::Assign(Box::new((
Place::from(promoted_ref),
Rvalue::Use(promoted_operand(ref_ty, span)),
))),
};
self.extra_statements.push((loc, promoted_ref_statement));

Rvalue::Ref(
tcx.lifetimes.re_erased,
borrow_kind,
Place {
local: mem::replace(&mut place.local, promoted_ref),
projection: List::empty(),
},
)
}
_ => bug!(),
}
let loc = candidate.location;
let statement = &mut blocks[loc.block].statements[loc.statement_index];
match statement.kind {
StatementKind::Assign(box (
_,
Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
)) => {
// Use the underlying local for this (necessarily interior) borrow.
let ty = local_decls.local_decls()[place.local].ty;
let span = statement.source_info.span;

let ref_ty = tcx.mk_ref(
tcx.lifetimes.re_erased,
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
);

*region = tcx.lifetimes.re_erased;

let mut projection = vec![PlaceElem::Deref];
projection.extend(place.projection);
place.projection = tcx.intern_place_elems(&projection);

// Create a temp to hold the promoted reference.
// This is because `*r` requires `r` to be a local,
// otherwise we would use the `promoted` directly.
let mut promoted_ref = LocalDecl::new(ref_ty, span);
promoted_ref.source_info = statement.source_info;
let promoted_ref = local_decls.push(promoted_ref);
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);

let promoted_ref_statement = Statement {
source_info: statement.source_info,
kind: StatementKind::Assign(Box::new((
Place::from(promoted_ref),
Rvalue::Use(promoted_operand(ref_ty, span)),
))),
};
self.extra_statements.push((loc, promoted_ref_statement));

Rvalue::Ref(
tcx.lifetimes.re_erased,
borrow_kind,
Place {
local: mem::replace(&mut place.local, promoted_ref),
projection: List::empty(),
},
)
}
_ => bug!(),
}
};

Expand Down Expand Up @@ -964,25 +949,21 @@ pub fn promote_candidates<'tcx>(

let mut extra_statements = vec![];
for candidate in candidates.into_iter().rev() {
match candidate {
Candidate::Ref(Location { block, statement_index }) => {
if let StatementKind::Assign(box (place, _)) =
&body[block].statements[statement_index].kind
{
if let Some(local) = place.as_local() {
if temps[local] == TempState::PromotedOut {
// Already promoted.
continue;
}
}
let Location { block, statement_index } = candidate.location;
if let StatementKind::Assign(box (place, _)) = &body[block].statements[statement_index].kind
{
if let Some(local) = place.as_local() {
if temps[local] == TempState::PromotedOut {
// Already promoted.
continue;
}
}
}

// Declare return place local so that `mir::Body::new` doesn't complain.
let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect();

let mut scope = body.source_scopes[candidate.source_info(body).scope].clone();
let mut scope = body.source_scopes[body.source_info(candidate.location).scope].clone();
scope.parent_scope = None;

let promoted = Body::new(
Expand Down
Loading

0 comments on commit e8423e6

Please sign in to comment.