Skip to content

Rollup of 4 pull requests #92434

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

Merged
merged 9 commits into from
Dec 30, 2021
128 changes: 116 additions & 12 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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(),
}
}
}
4 changes: 3 additions & 1 deletion compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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("=");
Expand Down
20 changes: 11 additions & 9 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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>) {
Expand Down
3 changes: 1 addition & 2 deletions library/core/src/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
20 changes: 10 additions & 10 deletions src/test/pretty/nested-item-vis-defaultness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
6 changes: 3 additions & 3 deletions src/test/ui/macros/stringify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -402,7 +402,7 @@ fn test_item() {
stringify_item!(
const S: ();
),
"const S: () ;", // FIXME
"const S: ();",
);

// ItemKind::Fn
Expand Down
32 changes: 32 additions & 0 deletions src/test/ui/traits/issue-92292.rs
Original file line number Diff line number Diff line change
@@ -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() {}