Skip to content

Commit aa1e6db

Browse files
committed
Auto merge of #53002 - QuietMisdreavus:brother-may-i-have-some-loops, r=pnkfelix
make `everybody_loops` preserve item declarations First half of #52545. `everybody_loops` is used by rustdoc to ensure we don't contain erroneous references to platform APIs if one of its uses is pulled in by `#[doc(cfg)]`. However, you can also implement traits for public types inside of functions. This is used by Diesel (probably others, but they were the example that was reported) to get around a recent macro hygiene fix, which has caused their crate to fail to document. While this won't make the traits show up in documentation (that step comes later), it will at least allow files to be generated.
2 parents e9fa9f5 + 7e77d19 commit aa1e6db

File tree

3 files changed

+108
-24
lines changed

3 files changed

+108
-24
lines changed

src/librustc_driver/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#![feature(box_syntax)]
2222
#![cfg_attr(unix, feature(libc))]
23+
#![feature(option_replace)]
2324
#![feature(quote)]
2425
#![feature(rustc_diagnostic_macros)]
2526
#![feature(slice_sort_by_cached_key)]

src/librustc_driver/pretty.rs

+78-24
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use syntax::fold::{self, Folder};
3333
use syntax::print::{pprust};
3434
use syntax::print::pprust::PrintState;
3535
use syntax::ptr::P;
36+
use syntax::util::ThinVec;
3637
use syntax::util::small_vector::SmallVector;
3738
use syntax_pos::{self, FileName};
3839

@@ -650,18 +651,25 @@ impl UserIdentifiedItem {
650651
// [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401
651652
pub struct ReplaceBodyWithLoop<'a> {
652653
within_static_or_const: bool,
654+
nested_blocks: Option<Vec<ast::Block>>,
653655
sess: &'a Session,
654656
}
655657

656658
impl<'a> ReplaceBodyWithLoop<'a> {
657659
pub fn new(sess: &'a Session) -> ReplaceBodyWithLoop<'a> {
658-
ReplaceBodyWithLoop { within_static_or_const: false, sess }
660+
ReplaceBodyWithLoop {
661+
within_static_or_const: false,
662+
nested_blocks: None,
663+
sess
664+
}
659665
}
660666

661667
fn run<R, F: FnOnce(&mut Self) -> R>(&mut self, is_const: bool, action: F) -> R {
662668
let old_const = mem::replace(&mut self.within_static_or_const, is_const);
669+
let old_blocks = self.nested_blocks.take();
663670
let ret = action(self);
664671
self.within_static_or_const = old_const;
672+
self.nested_blocks = old_blocks;
665673
ret
666674
}
667675

@@ -739,42 +747,88 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
739747
self.run(is_const, |s| fold::noop_fold_impl_item(i, s))
740748
}
741749

750+
fn fold_anon_const(&mut self, c: ast::AnonConst) -> ast::AnonConst {
751+
self.run(true, |s| fold::noop_fold_anon_const(c, s))
752+
}
753+
742754
fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
743-
fn expr_to_block(rules: ast::BlockCheckMode,
755+
fn stmt_to_block(rules: ast::BlockCheckMode,
744756
recovered: bool,
745-
e: Option<P<ast::Expr>>,
746-
sess: &Session) -> P<ast::Block> {
747-
P(ast::Block {
748-
stmts: e.map(|e| {
749-
ast::Stmt {
750-
id: sess.next_node_id(),
751-
span: e.span,
752-
node: ast::StmtKind::Expr(e),
753-
}
754-
})
755-
.into_iter()
756-
.collect(),
757+
s: Option<ast::Stmt>,
758+
sess: &Session) -> ast::Block {
759+
ast::Block {
760+
stmts: s.into_iter().collect(),
757761
rules,
758762
id: sess.next_node_id(),
759763
span: syntax_pos::DUMMY_SP,
760764
recovered,
761-
})
765+
}
762766
}
763767

764-
if !self.within_static_or_const {
765-
766-
let empty_block = expr_to_block(BlockCheckMode::Default, false, None, self.sess);
767-
let loop_expr = P(ast::Expr {
768-
node: ast::ExprKind::Loop(empty_block, None),
769-
id: self.sess.next_node_id(),
768+
fn block_to_stmt(b: ast::Block, sess: &Session) -> ast::Stmt {
769+
let expr = P(ast::Expr {
770+
id: sess.next_node_id(),
771+
node: ast::ExprKind::Block(P(b), None),
770772
span: syntax_pos::DUMMY_SP,
771-
attrs: ast::ThinVec::new(),
773+
attrs: ThinVec::new(),
772774
});
773775

774-
expr_to_block(b.rules, b.recovered, Some(loop_expr), self.sess)
776+
ast::Stmt {
777+
id: sess.next_node_id(),
778+
node: ast::StmtKind::Expr(expr),
779+
span: syntax_pos::DUMMY_SP,
780+
}
781+
}
775782

776-
} else {
783+
let empty_block = stmt_to_block(BlockCheckMode::Default, false, None, self.sess);
784+
let loop_expr = P(ast::Expr {
785+
node: ast::ExprKind::Loop(P(empty_block), None),
786+
id: self.sess.next_node_id(),
787+
span: syntax_pos::DUMMY_SP,
788+
attrs: ast::ThinVec::new(),
789+
});
790+
791+
let loop_stmt = ast::Stmt {
792+
id: self.sess.next_node_id(),
793+
span: syntax_pos::DUMMY_SP,
794+
node: ast::StmtKind::Expr(loop_expr),
795+
};
796+
797+
if self.within_static_or_const {
777798
fold::noop_fold_block(b, self)
799+
} else {
800+
b.map(|b| {
801+
let mut stmts = vec![];
802+
for s in b.stmts {
803+
let old_blocks = self.nested_blocks.replace(vec![]);
804+
805+
stmts.extend(self.fold_stmt(s).into_iter().filter(|s| s.is_item()));
806+
807+
// we put a Some in there earlier with that replace(), so this is valid
808+
let new_blocks = self.nested_blocks.take().unwrap();
809+
self.nested_blocks = old_blocks;
810+
stmts.extend(new_blocks.into_iter().map(|b| block_to_stmt(b, &self.sess)));
811+
}
812+
813+
let mut new_block = ast::Block {
814+
stmts,
815+
..b
816+
};
817+
818+
if let Some(old_blocks) = self.nested_blocks.as_mut() {
819+
//push our fresh block onto the cache and yield an empty block with `loop {}`
820+
if !new_block.stmts.is_empty() {
821+
old_blocks.push(new_block);
822+
}
823+
824+
stmt_to_block(b.rules, b.recovered, Some(loop_stmt), self.sess)
825+
} else {
826+
//push `loop {}` onto the end of our fresh block and yield that
827+
new_block.stmts.push(loop_stmt);
828+
829+
new_block
830+
}
831+
})
778832
}
779833
}
780834

src/test/rustdoc/traits-in-bodies.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//prior to fixing `everybody_loops` to preserve items, rustdoc would crash on this file, as it
12+
//didn't see that `SomeStruct` implemented `Clone`
13+
14+
//FIXME(misdreavus): whenever rustdoc shows traits impl'd inside bodies, make sure this test
15+
//reflects that
16+
17+
pub struct Bounded<T: Clone>(T);
18+
19+
pub struct SomeStruct;
20+
21+
fn asdf() -> Bounded<SomeStruct> {
22+
impl Clone for SomeStruct {
23+
fn clone(&self) -> SomeStruct {
24+
SomeStruct
25+
}
26+
}
27+
28+
Bounded(SomeStruct)
29+
}

0 commit comments

Comments
 (0)