Remove the everybody loops pass

It isn't used anymore by rustdoc
This commit is contained in:
bjorn3 2021-06-25 11:56:14 +02:00
parent 4566094913
commit 2f84484aac
11 changed files with 12 additions and 309 deletions

View File

@ -42,7 +42,7 @@ where
F: FnOnce(&dyn PrinterSupport) -> A,
{
match *ppmode {
Normal | EveryBodyLoops | Expanded => {
Normal | Expanded => {
let annotation = NoAnn { sess, tcx };
f(&annotation)
}

View File

@ -3,7 +3,6 @@ use crate::proc_macro_decls;
use crate::util;
use ast::CRATE_NODE_ID;
use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::{self as ast, visit};
use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::back::link::emit_metadata;
@ -29,7 +28,7 @@ use rustc_plugin_impl as plugin;
use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
use rustc_resolve::{Resolver, ResolverArenas};
use rustc_serialize::json;
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode};
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata};
@ -384,11 +383,6 @@ pub fn configure_and_expand(
rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate)
});
if let Some(PpMode::Source(PpSourceMode::EveryBodyLoops)) = sess.opts.pretty {
tracing::debug!("replacing bodies with loop {{}}");
util::ReplaceBodyWithLoop::new(resolver).visit_crate(&mut krate);
}
let has_proc_macro_decls = sess.time("AST_validation", || {
rustc_ast_passes::ast_validation::check_crate(sess, &krate, resolver.lint_buffer())
});
@ -457,18 +451,12 @@ pub fn configure_and_expand(
});
// Add all buffered lints from the `ParseSess` to the `Session`.
// The ReplaceBodyWithLoop pass may have deleted some AST nodes, potentially
// causing a delay_span_bug later if a buffered lint refers to such a deleted
// AST node (issue #87308). Since everybody_loops is for pretty-printing only,
// anyway, we simply skip all buffered lints here.
if !matches!(sess.opts.pretty, Some(PpMode::Source(PpSourceMode::EveryBodyLoops))) {
sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
info!("{} parse sess buffered_lints", buffered_lints.len());
for early_lint in buffered_lints.drain(..) {
resolver.lint_buffer().add_early_lint(early_lint);
}
});
}
sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
info!("{} parse sess buffered_lints", buffered_lints.len());
for early_lint in buffered_lints.drain(..) {
resolver.lint_buffer().add_early_lint(early_lint);
}
});
// Gate identifiers containing invalid Unicode codepoints that were recovered during lexing.
sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| {

View File

@ -1,7 +1,5 @@
use libloading::Library;
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Term};
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
@ -13,7 +11,6 @@ use rustc_middle::ty::tls;
use rustc_parse::validate_attr;
#[cfg(parallel_compiler)]
use rustc_query_impl::QueryCtxt;
use rustc_resolve::{self, Resolver};
use rustc_session as session;
use rustc_session::config::CheckCfg;
use rustc_session::config::{self, CrateType};
@ -25,12 +22,10 @@ use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::FileLoader;
use rustc_span::symbol::{sym, Symbol};
use smallvec::SmallVec;
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::lazy::SyncOnceCell;
use std::mem;
use std::ops::DerefMut;
#[cfg(not(parallel_compiler))]
use std::panic;
use std::path::{Path, PathBuf};
@ -664,214 +659,6 @@ pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
std::fs::rename(src, dst)
}
/// Replaces function bodies with `loop {}` (an infinite loop). This gets rid of
/// all semantic errors in the body while still satisfying the return type,
/// except in certain cases, see below for more.
///
/// This pass is known as `everybody_loops`. Very punny.
///
/// As of March 2021, `everybody_loops` is only used for the
/// `-Z unpretty=everybody_loops` debugging option.
///
/// FIXME: Currently the `everybody_loops` transformation is not applied to:
/// * `const fn`; support could be added, but hasn't. Originally `const fn`
/// was skipped due to issue #43636 that `loop` was not supported for
/// const evaluation.
/// * `impl Trait`, due to issue #43869 that functions returning impl Trait cannot be diverging.
/// Solving this may require `!` to implement every trait, which relies on the an even more
/// ambitious form of the closed RFC #1637. See also [#34511].
///
/// [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401
pub struct ReplaceBodyWithLoop<'a, 'b> {
within_static_or_const: bool,
nested_blocks: Option<Vec<ast::Block>>,
resolver: &'a mut Resolver<'b>,
}
impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
pub fn new(resolver: &'a mut Resolver<'b>) -> ReplaceBodyWithLoop<'a, 'b> {
ReplaceBodyWithLoop { within_static_or_const: false, nested_blocks: None, resolver }
}
fn run<R, F: FnOnce(&mut Self) -> R>(&mut self, is_const: bool, action: F) -> R {
let old_const = mem::replace(&mut self.within_static_or_const, is_const);
let old_blocks = self.nested_blocks.take();
let ret = action(self);
self.within_static_or_const = old_const;
self.nested_blocks = old_blocks;
ret
}
fn should_ignore_fn(ret_ty: &ast::FnRetTy) -> bool {
let ast::FnRetTy::Ty(ref ty) = ret_ty else {
return false;
};
fn involves_impl_trait(ty: &ast::Ty) -> bool {
match ty.kind {
ast::TyKind::ImplTrait(..) => true,
ast::TyKind::Slice(ref subty)
| ast::TyKind::Array(ref subty, _)
| ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. })
| ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. })
| ast::TyKind::Paren(ref subty) => involves_impl_trait(subty),
ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()),
ast::TyKind::Path(_, ref path) => {
path.segments.iter().any(|seg| match seg.args.as_deref() {
None => false,
Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
data.args.iter().any(|arg| match arg {
ast::AngleBracketedArg::Arg(arg) => match arg {
ast::GenericArg::Type(ty) => involves_impl_trait(ty),
ast::GenericArg::Lifetime(_) | ast::GenericArg::Const(_) => {
false
}
},
ast::AngleBracketedArg::Constraint(c) => match c.kind {
ast::AssocConstraintKind::Bound { .. } => true,
ast::AssocConstraintKind::Equality { ref term } => {
match term {
Term::Ty(ty) => involves_impl_trait(ty),
// FIXME(...): This should check if the constant
// involves a trait impl, but for now ignore.
Term::Const(_) => false,
}
}
},
})
}
Some(&ast::GenericArgs::Parenthesized(ref data)) => {
any_involves_impl_trait(data.inputs.iter())
|| ReplaceBodyWithLoop::should_ignore_fn(&data.output)
}
})
}
_ => false,
}
}
fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool {
it.any(|subty| involves_impl_trait(subty))
}
involves_impl_trait(ty)
}
fn is_sig_const(sig: &ast::FnSig) -> bool {
matches!(sig.header.constness, ast::Const::Yes(_))
|| ReplaceBodyWithLoop::should_ignore_fn(&sig.decl.output)
}
}
impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
fn visit_item_kind(&mut self, i: &mut ast::ItemKind) {
let is_const = match i {
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_visit_item_kind(i, s))
}
fn flat_map_trait_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let is_const = match i.kind {
ast::AssocItemKind::Const(..) => true,
ast::AssocItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
}
fn flat_map_impl_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
self.flat_map_trait_item(i)
}
fn visit_anon_const(&mut self, c: &mut ast::AnonConst) {
self.run(true, |s| noop_visit_anon_const(c, s))
}
fn visit_block(&mut self, b: &mut P<ast::Block>) {
fn stmt_to_block(
rules: ast::BlockCheckMode,
s: Option<ast::Stmt>,
resolver: &mut Resolver<'_>,
) -> ast::Block {
ast::Block {
stmts: s.into_iter().collect(),
rules,
id: resolver.next_node_id(),
span: rustc_span::DUMMY_SP,
tokens: None,
could_be_bare_literal: false,
}
}
fn block_to_stmt(b: ast::Block, resolver: &mut Resolver<'_>) -> ast::Stmt {
let expr = P(ast::Expr {
id: resolver.next_node_id(),
kind: ast::ExprKind::Block(P(b), None),
span: rustc_span::DUMMY_SP,
attrs: AttrVec::new(),
tokens: None,
});
ast::Stmt {
id: resolver.next_node_id(),
kind: ast::StmtKind::Expr(expr),
span: rustc_span::DUMMY_SP,
}
}
let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.resolver);
let loop_expr = P(ast::Expr {
kind: ast::ExprKind::Loop(P(empty_block), None),
id: self.resolver.next_node_id(),
span: rustc_span::DUMMY_SP,
attrs: AttrVec::new(),
tokens: None,
});
let loop_stmt = ast::Stmt {
id: self.resolver.next_node_id(),
span: rustc_span::DUMMY_SP,
kind: ast::StmtKind::Expr(loop_expr),
};
if self.within_static_or_const {
noop_visit_block(b, self)
} else {
visit_clobber(b.deref_mut(), |b| {
let mut stmts = vec![];
for s in b.stmts {
let old_blocks = self.nested_blocks.replace(vec![]);
stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item()));
// we put a Some in there earlier with that replace(), so this is valid
let new_blocks = self.nested_blocks.take().unwrap();
self.nested_blocks = old_blocks;
stmts.extend(new_blocks.into_iter().map(|b| block_to_stmt(b, self.resolver)));
}
let mut new_block = ast::Block { stmts, ..b };
if let Some(old_blocks) = self.nested_blocks.as_mut() {
//push our fresh block onto the cache and yield an empty block with `loop {}`
if !new_block.stmts.is_empty() {
old_blocks.push(new_block);
}
stmt_to_block(b.rules, Some(loop_stmt), &mut self.resolver)
} else {
//push `loop {}` onto the end of our fresh block and yield that
new_block.stmts.push(loop_stmt);
new_block
}
})
}
}
}
/// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)"
pub fn version_str() -> Option<&'static str> {
option_env!("CFG_VERSION")

View File

@ -2509,7 +2509,6 @@ fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Opt
let first = match debugging_opts.unpretty.as_deref()? {
"normal" => Source(PpSourceMode::Normal),
"identified" => Source(PpSourceMode::Identified),
"everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
"expanded" => Source(PpSourceMode::Expanded),
"expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
"expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
@ -2645,8 +2644,6 @@ impl fmt::Display for CrateType {
pub enum PpSourceMode {
/// `-Zunpretty=normal`
Normal,
/// `-Zunpretty=everybody_loops`
EveryBodyLoops,
/// `-Zunpretty=expanded`
Expanded,
/// `-Zunpretty=identified`
@ -2678,7 +2675,7 @@ pub enum PpHirMode {
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpMode {
/// Options that print the source code, i.e.
/// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
/// `-Zunpretty=normal` and `-Zunpretty=expanded`
Source(PpSourceMode),
AstTree(PpAstTreeMode),
/// Options that print the HIR, i.e. `-Zunpretty=hir`
@ -2700,7 +2697,7 @@ impl PpMode {
match *self {
Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
Source(Expanded | ExpandedIdentified | ExpandedHygiene)
| AstTree(PpAstTreeMode::Expanded)
| Hir(_)
| HirTree

View File

@ -1491,7 +1491,6 @@ options! {
`normal`, `identified`,
`expanded`, `expanded,identified`,
`expanded,hygiene` (with internal representations),
`everybody_loops` (all function bodies replaced with `loop {}`),
`ast-tree` (raw AST before expansion),
`ast-tree,expanded` (raw AST after expansion),
`hir` (the HIR), `hir,identified`,

View File

@ -82,8 +82,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
// The `def_id` here actually was calculated during resolution (at least
// at the time of this writing) and is being shipped to us via a side
// channel of the tcx. There may have been extra expansion phases,
// however, which ended up removing the `def_id` *after* expansion such
// as the `ReplaceBodyWithLoop` pass (which is a bit of a hack, but hey)
// however, which ended up removing the `def_id` *after* expansion.
//
// As a result we need to verify that `def_id` is indeed still valid for
// our AST and actually present in the HIR map. If it's not there then

View File

@ -1,12 +0,0 @@
// Regression test for issue #87308.
// compile-flags: -Zunpretty=everybody_loops
// check-pass
macro_rules! foo {
() => { break 'x; }
}
pub fn main() {
'x: loop { foo!() }
}

View File

@ -1,14 +0,0 @@
#![feature(prelude_import)]
#![no_std]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
// Regression test for issue #87308.
// compile-flags: -Zunpretty=everybody_loops
// check-pass
macro_rules! foo { () => { break 'x ; } }
pub fn main() { loop {} }

View File

@ -1,9 +0,0 @@
error[E0565]: meta item in `repr` must be an identifier
--> $DIR/issue-83921-pretty.rs:10:8
|
LL | #[repr("C")]
| ^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0565`.

View File

@ -1,18 +0,0 @@
#![feature(prelude_import)]
#![no_std]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
// Regression test for #83921. A `delay_span_bug()` call was issued, but the
// error was never reported because the pass responsible for detecting and
// reporting the error does not run in certain modes of pretty-printing.
// Make sure the error is reported if we do not just pretty-print:
// revisions: pretty normal
// [pretty]compile-flags: -Zunpretty=everybody_loops
// [pretty]check-pass
#[repr("C")]
struct A {}
fn main() { loop {} }

View File

@ -1,14 +0,0 @@
// Regression test for #83921. A `delay_span_bug()` call was issued, but the
// error was never reported because the pass responsible for detecting and
// reporting the error does not run in certain modes of pretty-printing.
// Make sure the error is reported if we do not just pretty-print:
// revisions: pretty normal
// [pretty]compile-flags: -Zunpretty=everybody_loops
// [pretty]check-pass
#[repr("C")]
//[normal]~^ ERROR: meta item in `repr` must be an identifier [E0565]
struct A {}
fn main() {}