Auto merge of #92434 - matthiaskrgr:rollup-m8wuq0v, r=matthiaskrgr

Rollup of 4 pull requests

Successful merges:

 - #91519 (ast: Avoid aborts on fatal errors thrown from mutable AST visitor)
 - #92414 (Fix spacing of pretty printed const item without body)
 - #92423 (Add UI test for #92292)
 - #92427 (Use `UnsafeCell::get_mut()` in `core::lazy::OnceCell::get_mut()`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2021-12-30 14:52:50 +00:00
commit b60e32c828
7 changed files with 176 additions and 37 deletions

View File

@ -14,13 +14,14 @@ use crate::tokenstream::*;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Ident;
use rustc_span::Span;
use smallvec::{smallvec, Array, SmallVec};
use std::ops::DerefMut;
use std::{panic, process, ptr};
use std::{panic, ptr};
pub trait ExpectOne<A: Array> {
fn expect_one(self, err: &'static str) -> A::Item;
@ -283,23 +284,21 @@ pub trait MutVisitor: Sized {
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
/// method. Abort the program if the closure panics.
///
/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler.
/// Instead of aborting on catching a panic we need to reset the visited node to some valid but
/// possibly meaningless value and rethrow the panic.
/// method.
//
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_clobber<T, F>(t: &mut T, f: F)
where
F: FnOnce(T) -> T,
{
pub fn visit_clobber<T: DummyAstNode>(t: &mut T, f: impl FnOnce(T) -> T) {
unsafe {
// Safe because `t` is used in a read-only fashion by `read()` before
// being overwritten by `write()`.
let old_t = ptr::read(t);
let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t)))
.unwrap_or_else(|_| process::abort());
let new_t =
panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))).unwrap_or_else(|err| {
// Set `t` to some valid but possible meaningless value,
// and pass the fatal error further.
ptr::write(t, T::dummy());
panic::resume_unwind(err);
});
ptr::write(t, new_t);
}
}
@ -1454,3 +1453,108 @@ pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
}
vis.visit_span(&mut visibility.span);
}
/// Some value for the AST node that is valid but possibly meaningless.
pub trait DummyAstNode {
fn dummy() -> Self;
}
impl<T> DummyAstNode for Option<T> {
fn dummy() -> Self {
Default::default()
}
}
impl<T: DummyAstNode + 'static> DummyAstNode for P<T> {
fn dummy() -> Self {
P(DummyAstNode::dummy())
}
}
impl<T> DummyAstNode for ThinVec<T> {
fn dummy() -> Self {
Default::default()
}
}
impl DummyAstNode for Item {
fn dummy() -> Self {
Item {
attrs: Default::default(),
id: DUMMY_NODE_ID,
span: Default::default(),
vis: Visibility {
kind: VisibilityKind::Public,
span: Default::default(),
tokens: Default::default(),
},
ident: Ident::empty(),
kind: ItemKind::ExternCrate(None),
tokens: Default::default(),
}
}
}
impl DummyAstNode for Expr {
fn dummy() -> Self {
Expr {
id: DUMMY_NODE_ID,
kind: ExprKind::Err,
span: Default::default(),
attrs: Default::default(),
tokens: Default::default(),
}
}
}
impl DummyAstNode for Ty {
fn dummy() -> Self {
Ty {
id: DUMMY_NODE_ID,
kind: TyKind::Err,
span: Default::default(),
tokens: Default::default(),
}
}
}
impl DummyAstNode for Pat {
fn dummy() -> Self {
Pat {
id: DUMMY_NODE_ID,
kind: PatKind::Wild,
span: Default::default(),
tokens: Default::default(),
}
}
}
impl DummyAstNode for Stmt {
fn dummy() -> Self {
Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Empty, span: Default::default() }
}
}
impl DummyAstNode for Block {
fn dummy() -> Self {
Block {
stmts: Default::default(),
id: DUMMY_NODE_ID,
rules: BlockCheckMode::Default,
span: Default::default(),
tokens: Default::default(),
could_be_bare_literal: Default::default(),
}
}
}
impl DummyAstNode for Crate {
fn dummy() -> Self {
Crate {
attrs: Default::default(),
items: Default::default(),
span: Default::default(),
is_placeholder: Default::default(),
}
}
}

View File

@ -1116,7 +1116,9 @@ impl<'a> State<'a> {
self.print_ident(ident);
self.word_space(":");
self.print_type(ty);
self.space();
if body.is_some() {
self.space();
}
self.end(); // end the head-ibox
if let Some(body) = body {
self.word_space("=");

View File

@ -1160,13 +1160,18 @@ macro_rules! assign_id {
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn visit_crate(&mut self, krate: &mut ast::Crate) {
let span = krate.span;
let empty_crate =
|| ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None };
let mut fold_crate = |krate: ast::Crate| {
visit_clobber(krate, |krate| {
let span = krate.span;
let mut krate = match self.configure(krate) {
Some(krate) => krate,
None => return empty_crate(),
None => {
return ast::Crate {
attrs: Vec::new(),
items: Vec::new(),
span,
is_placeholder: None,
};
}
};
if let Some(attr) = self.take_first_attr(&mut krate) {
@ -1177,10 +1182,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
noop_visit_crate(&mut krate, self);
krate
};
// Cannot use `visit_clobber` here, see the FIXME on it.
*krate = fold_crate(mem::replace(krate, empty_crate()));
})
}
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {

View File

@ -102,8 +102,7 @@ impl<T> OnceCell<T> {
/// Returns `None` if the cell is empty.
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get_mut(&mut self) -> Option<&mut T> {
// SAFETY: Safe because we have unique access
unsafe { &mut *self.inner.get() }.as_mut()
self.inner.get_mut().as_mut()
}
/// Sets the contents of the cell to `value`.

View File

@ -6,42 +6,42 @@ fn main() {}
#[cfg(FALSE)]
extern "C" {
static X: u8 ;
static X: u8;
type X;
fn foo();
pub static X: u8 ;
pub static X: u8;
pub type X;
pub fn foo();
}
#[cfg(FALSE)]
trait T {
const X: u8 ;
const X: u8;
type X;
fn foo();
default const X: u8 ;
default const X: u8;
default type X;
default fn foo();
pub const X: u8 ;
pub const X: u8;
pub type X;
pub fn foo();
pub default const X: u8 ;
pub default const X: u8;
pub default type X;
pub default fn foo();
}
#[cfg(FALSE)]
impl T for S {
const X: u8 ;
const X: u8;
type X;
fn foo();
default const X: u8 ;
default const X: u8;
default type X;
default fn foo();
pub const X: u8 ;
pub const X: u8;
pub type X;
pub fn foo();
pub default const X: u8 ;
pub default const X: u8;
pub default type X;
pub default fn foo();
}

View File

@ -382,13 +382,13 @@ fn test_item() {
stringify_item!(
static S: ();
),
"static S: () ;", // FIXME
"static S: ();",
);
assert_eq!(
stringify_item!(
static mut S: ();
),
"static mut S: () ;",
"static mut S: ();",
);
// ItemKind::Const
@ -402,7 +402,7 @@ fn test_item() {
stringify_item!(
const S: ();
),
"const S: () ;", // FIXME
"const S: ();",
);
// ItemKind::Fn

View File

@ -0,0 +1,32 @@
// check-pass
use std::marker::PhantomData;
pub struct MyGenericType<T> {
_marker: PhantomData<*const T>,
}
pub struct MyNonGenericType;
impl<T> From<MyGenericType<T>> for MyNonGenericType {
fn from(_: MyGenericType<T>) -> Self {
todo!()
}
}
pub trait MyTrait {
const MY_CONSTANT: i32;
}
impl<T> MyTrait for MyGenericType<T>
where
Self: Into<MyNonGenericType>,
{
const MY_CONSTANT: i32 = 1;
}
impl<T> MyGenericType<T> {
const MY_OTHER_CONSTANT: i32 = <MyGenericType<T> as MyTrait>::MY_CONSTANT;
}
fn main() {}