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

Fix stack overflows when compiling high-recursion_limit programs #93056

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3818,6 +3818,7 @@ version = "0.0.0"
dependencies = [
"rustc_ast",
"rustc_ast_pretty",
"rustc_data_structures",
"rustc_hir",
"rustc_span",
"rustc_target",
Expand Down
59 changes: 39 additions & 20 deletions compiler/rustc_ast/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,36 @@
//! implementation changes (using a special thread-local heap, for example).
//! Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.

use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};

use std::fmt::{self, Debug, Display};
use std::iter::FromIterator;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::{slice, vec};

use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};

use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
/// An owned smart pointer.
pub struct P<T: ?Sized> {
ptr: Box<T>,
ptr: ManuallyDrop<Box<T>>,
}

/// Construct a `P<T>` from a `T` value.
#[allow(non_snake_case)]
pub fn P<T: 'static>(value: T) -> P<T> {
P { ptr: Box::new(value) }
P::from_box(Box::new(value))
}

impl<T: ?Sized> P<T> {
const fn from_box(ptr: Box<T>) -> P<T> {
P { ptr: ManuallyDrop::new(ptr) }
}

fn into_box(self) -> Box<T> {
let mut this = ManuallyDrop::new(self);
unsafe { ManuallyDrop::take(&mut this.ptr) }
}
}

impl<T: 'static> P<T> {
Expand All @@ -47,32 +60,38 @@ impl<T: 'static> P<T> {
where
F: FnOnce(T) -> U,
{
f(*self.ptr)
f(*self.into_box())
}

/// Equivalent to `and_then(|x| x)`.
pub fn into_inner(self) -> T {
*self.ptr
*self.into_box()
}

/// Produce a new `P<T>` from `self` without reallocating.
pub fn map<F>(mut self, f: F) -> P<T>
pub fn map<F>(self, f: F) -> P<T>
where
F: FnOnce(T) -> T,
{
let x = f(*self.ptr);
*self.ptr = x;

self
let mut ptr = self.into_box();
*ptr = f(*ptr);
P::from_box(ptr)
}

/// Optionally produce a new `P<T>` from `self` without reallocating.
pub fn filter_map<F>(mut self, f: F) -> Option<P<T>>
pub fn filter_map<F>(self, f: F) -> Option<P<T>>
where
F: FnOnce(T) -> Option<T>,
{
*self.ptr = f(*self.ptr)?;
Some(self)
let mut ptr = self.into_box();
*ptr = f(*ptr)?;
Some(P::from_box(ptr))
}
}

impl<T: ?Sized> Drop for P<T> {
fn drop(&mut self) {
ensure_sufficient_stack(|| unsafe { ManuallyDrop::drop(&mut self.ptr) });
}
}

Expand All @@ -98,7 +117,7 @@ impl<T: 'static + Clone> Clone for P<T> {

impl<T: ?Sized + Debug> Debug for P<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.ptr, f)
Debug::fmt(&*self.ptr, f)
}
}

Expand All @@ -110,7 +129,7 @@ impl<T: Display> Display for P<T> {

impl<T> fmt::Pointer for P<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.ptr, f)
fmt::Pointer::fmt(&*self.ptr, f)
}
}

Expand All @@ -128,17 +147,17 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {

impl<T> P<[T]> {
pub const fn new() -> P<[T]> {
P { ptr: Box::default() }
P::from_box(Box::default())
}

#[inline(never)]
pub fn from_vec(v: Vec<T>) -> P<[T]> {
P { ptr: v.into_boxed_slice() }
P::from_box(v.into_boxed_slice())
}

#[inline(never)]
pub fn into_vec(self) -> Vec<T> {
self.ptr.into_vec()
self.into_box().into_vec()
}
}

Expand Down
13 changes: 7 additions & 6 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use crate::ast::*;
use crate::token;

use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;

Expand Down Expand Up @@ -411,7 +412,7 @@ pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) {
}

pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
match typ.kind {
ensure_sufficient_stack(|| match typ.kind {
TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => visitor.visit_ty(ty),
TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
TyKind::Rptr(ref opt_lifetime, ref mutable_type) => {
Expand Down Expand Up @@ -445,7 +446,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
TyKind::Never | TyKind::CVarArgs => {}
}
})
}

pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) {
Expand Down Expand Up @@ -721,7 +722,7 @@ pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) {
}

pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
match statement.kind {
ensure_sufficient_stack(|| match statement.kind {
StmtKind::Local(ref local) => visitor.visit_local(local),
StmtKind::Item(ref item) => visitor.visit_item(item),
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr),
Expand All @@ -733,7 +734,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
visitor.visit_attribute(attr);
}
}
}
})
}

pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) {
Expand Down Expand Up @@ -773,7 +774,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA
pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
walk_list!(visitor, visit_attribute, expression.attrs.iter());

match expression.kind {
ensure_sufficient_stack(|| match expression.kind {
ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
ExprKind::Array(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
Expand Down Expand Up @@ -902,7 +903,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Try(ref subexpression) => visitor.visit_expr(subexpression),
ExprKind::TryBlock(ref body) => visitor.visit_block(body),
ExprKind::Lit(_) | ExprKind::Err => {}
}
});

visitor.visit_expr_post(expression)
}
Expand Down
Loading