2 use rustc_ast
::ast
::{AttrVec, BlockCheckMode}
;
3 use rustc_ast
::mut_visit
::{visit_clobber, MutVisitor, *}
;
5 use rustc_ast
::util
::lev_distance
::find_best_match_for_name
;
6 use rustc_ast
::{self, ast}
;
7 use rustc_codegen_ssa
::traits
::CodegenBackend
;
8 use rustc_data_structures
::fingerprint
::Fingerprint
;
9 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
10 #[cfg(parallel_compiler)]
11 use rustc_data_structures
::jobserver
;
12 use rustc_data_structures
::stable_hasher
::StableHasher
;
13 use rustc_data_structures
::sync
::{Lock, Lrc}
;
14 use rustc_errors
::registry
::Registry
;
15 use rustc_metadata
::dynamic_lib
::DynamicLibrary
;
17 use rustc_resolve
::{self, Resolver}
;
18 use rustc_session
as session
;
19 use rustc_session
::config
::{self, CrateType}
;
20 use rustc_session
::config
::{ErrorOutputType, Input, OutputFilenames}
;
21 use rustc_session
::lint
::{self, BuiltinLintDiagnostics, LintBuffer}
;
22 use rustc_session
::parse
::CrateConfig
;
23 use rustc_session
::CrateDisambiguator
;
24 use rustc_session
::{early_error, filesearch, output, DiagnosticOutput, Session}
;
25 use rustc_span
::edition
::Edition
;
26 use rustc_span
::source_map
::FileLoader
;
27 use rustc_span
::symbol
::{sym, Symbol}
;
28 use smallvec
::SmallVec
;
30 use std
::io
::{self, Write}
;
32 use std
::ops
::DerefMut
;
33 use std
::path
::{Path, PathBuf}
;
34 use std
::sync
::{Arc, Mutex, Once}
;
35 #[cfg(not(parallel_compiler))]
36 use std
::{panic, thread}
;
38 /// Adds `target_feature = "..."` cfgs for a variety of platform
39 /// specific features (SSE, NEON etc.).
41 /// This is performed by checking whether a set of permitted features
42 /// is available on the target machine, by querying LLVM.
43 pub fn add_configuration(
44 cfg
: &mut CrateConfig
,
46 codegen_backend
: &dyn CodegenBackend
,
48 let tf
= sym
::target_feature
;
50 let target_features
= codegen_backend
.target_features(sess
);
51 sess
.target_features
.extend(target_features
.iter().cloned());
53 cfg
.extend(target_features
.into_iter().map(|feat
| (tf
, Some(feat
))));
55 if sess
.crt_static(None
) {
56 cfg
.insert((tf
, Some(Symbol
::intern("crt-static"))));
60 pub fn create_session(
61 sopts
: config
::Options
,
62 cfg
: FxHashSet
<(String
, Option
<String
>)>,
63 diagnostic_output
: DiagnosticOutput
,
64 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
+ '
static>>,
65 input_path
: Option
<PathBuf
>,
66 lint_caps
: FxHashMap
<lint
::LintId
, lint
::Level
>,
67 descriptions
: Registry
,
68 ) -> (Lrc
<Session
>, Lrc
<Box
<dyn CodegenBackend
>>) {
69 let mut sess
= session
::build_session(
78 let codegen_backend
= get_codegen_backend(&sess
);
80 let mut cfg
= config
::build_configuration(&sess
, config
::to_crate_config(cfg
));
81 add_configuration(&mut cfg
, &mut sess
, &*codegen_backend
);
82 sess
.parse_sess
.config
= cfg
;
84 (Lrc
::new(sess
), Lrc
::new(codegen_backend
))
87 const STACK_SIZE
: usize = 8 * 1024 * 1024;
89 fn get_stack_size() -> Option
<usize> {
90 // FIXME: Hacks on hacks. If the env is trying to override the stack size
91 // then *don't* set it explicitly.
92 env
::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE
)
95 struct Sink(Arc
<Mutex
<Vec
<u8>>>);
97 fn write(&mut self, data
: &[u8]) -> io
::Result
<usize> {
98 Write
::write(&mut *self.0.lock().unwrap(), data
)
100 fn flush(&mut self) -> io
::Result
<()> {
105 /// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
106 /// for `'static` bounds.
107 #[cfg(not(parallel_compiler))]
108 pub fn scoped_thread
<F
: FnOnce() -> R
+ Send
, R
: Send
>(cfg
: thread
::Builder
, f
: F
) -> R
{
110 unsafe impl Send
for Ptr {}
111 unsafe impl Sync
for Ptr {}
114 let run
= Ptr(&mut f
as *mut _
as *mut ());
115 let mut result
= None
;
116 let result_ptr
= Ptr(&mut result
as *mut _
as *mut ());
118 let thread
= cfg
.spawn(move || {
119 let run
= unsafe { (*(run.0 as *mut Option<F>)).take().unwrap() }
;
120 let result
= unsafe { &mut *(result_ptr.0 as *mut Option<R>) }
;
121 *result
= Some(run());
124 match thread
.unwrap().join() {
125 Ok(()) => result
.unwrap(),
126 Err(p
) => panic
::resume_unwind(p
),
130 #[cfg(not(parallel_compiler))]
131 pub fn setup_callbacks_and_run_in_thread_pool_with_globals
<F
: FnOnce() -> R
+ Send
, R
: Send
>(
134 stderr
: &Option
<Arc
<Mutex
<Vec
<u8>>>>,
137 let mut cfg
= thread
::Builder
::new().name("rustc".to_string());
139 if let Some(size
) = get_stack_size() {
140 cfg
= cfg
.stack_size(size
);
143 crate::callbacks
::setup_callbacks();
145 let main_handler
= move || {
146 rustc_ast
::with_session_globals(edition
, || {
147 ty
::tls
::GCX_PTR
.set(&Lock
::new(0), || {
148 if let Some(stderr
) = stderr
{
149 io
::set_panic(Some(box Sink(stderr
.clone())));
156 scoped_thread(cfg
, main_handler
)
159 #[cfg(parallel_compiler)]
160 pub fn setup_callbacks_and_run_in_thread_pool_with_globals
<F
: FnOnce() -> R
+ Send
, R
: Send
>(
163 stderr
: &Option
<Arc
<Mutex
<Vec
<u8>>>>,
166 crate::callbacks
::setup_callbacks();
168 let mut config
= rayon
::ThreadPoolBuilder
::new()
169 .thread_name(|_
| "rustc".to_string())
170 .acquire_thread_handler(jobserver
::acquire_thread
)
171 .release_thread_handler(jobserver
::release_thread
)
172 .num_threads(threads
)
173 .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }
);
175 if let Some(size
) = get_stack_size() {
176 config
= config
.stack_size(size
);
179 let with_pool
= move |pool
: &rayon
::ThreadPool
| pool
.install(move || f());
181 rustc_ast
::with_session_globals(edition
, || {
182 rustc_ast
::SESSION_GLOBALS
.with(|ast_session_globals
| {
183 rustc_span
::SESSION_GLOBALS
.with(|span_session_globals
| {
184 // The main handler runs for each Rayon worker thread and sets
185 // up the thread local rustc uses. ast_session_globals and
186 // span_session_globals are captured and set on the new
187 // threads. ty::tls::with_thread_locals sets up thread local
188 // callbacks from librustc_ast.
189 let main_handler
= move |thread
: rayon
::ThreadBuilder
| {
190 rustc_ast
::SESSION_GLOBALS
.set(ast_session_globals
, || {
191 rustc_span
::SESSION_GLOBALS
.set(span_session_globals
, || {
192 ty
::tls
::GCX_PTR
.set(&Lock
::new(0), || {
193 if let Some(stderr
) = stderr
{
194 io
::set_panic(Some(box Sink(stderr
.clone())));
202 config
.build_scoped(main_handler
, with_pool
).unwrap()
208 fn load_backend_from_dylib(path
: &Path
) -> fn() -> Box
<dyn CodegenBackend
> {
209 let lib
= DynamicLibrary
::open(path
).unwrap_or_else(|err
| {
210 let err
= format
!("couldn't load codegen backend {:?}: {:?}", path
, err
);
211 early_error(ErrorOutputType
::default(), &err
);
214 match lib
.symbol("__rustc_codegen_backend") {
217 mem
::transmute
::<*mut u8, _
>(f
)
221 "couldn't load codegen backend as it \
222 doesn't export the `__rustc_codegen_backend` \
226 early_error(ErrorOutputType
::default(), &err
);
232 pub fn get_codegen_backend(sess
: &Session
) -> Box
<dyn CodegenBackend
> {
233 static INIT
: Once
= Once
::new();
235 static mut LOAD
: fn() -> Box
<dyn CodegenBackend
> = || unreachable
!();
238 let codegen_name
= sess
243 .unwrap_or(&sess
.target
.target
.options
.codegen_backend
);
244 let backend
= match &codegen_name
[..] {
245 filename
if filename
.contains('
.'
) => load_backend_from_dylib(filename
.as_ref()),
246 codegen_name
=> get_builtin_codegen_backend(codegen_name
),
253 let backend
= unsafe { LOAD() }
;
258 // This is used for rustdoc, but it uses similar machinery to codegen backend
259 // loading, so we leave the code here. It is potentially useful for other tools
260 // that want to invoke the rustc binary while linking to rustc as well.
261 pub fn rustc_path
<'a
>() -> Option
<&'a Path
> {
262 static RUSTC_PATH
: once_cell
::sync
::OnceCell
<Option
<PathBuf
>> =
263 once_cell
::sync
::OnceCell
::new();
265 const BIN_PATH
: &str = env
!("RUSTC_INSTALL_BINDIR");
267 RUSTC_PATH
.get_or_init(|| get_rustc_path_inner(BIN_PATH
)).as_ref().map(|v
| &**v
)
270 fn get_rustc_path_inner(bin_path
: &str) -> Option
<PathBuf
> {
271 sysroot_candidates().iter().find_map(|sysroot
| {
272 let candidate
= sysroot
.join(bin_path
).join(if cfg
!(target_os
= "windows") {
277 candidate
.exists().then_some(candidate
)
281 fn sysroot_candidates() -> Vec
<PathBuf
> {
282 let target
= session
::config
::host_triple();
283 let mut sysroot_candidates
= vec
![filesearch
::get_or_default_sysroot()];
284 let path
= current_dll_path().and_then(|s
| s
.canonicalize().ok());
285 if let Some(dll
) = path
{
286 // use `parent` twice to chop off the file name and then also the
287 // directory containing the dll which should be either `lib` or `bin`.
288 if let Some(path
) = dll
.parent().and_then(|p
| p
.parent()) {
289 // The original `path` pointed at the `rustc_driver` crate's dll.
290 // Now that dll should only be in one of two locations. The first is
291 // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
292 // other is the target's libdir, for example
293 // `$sysroot/lib/rustlib/$target/lib/*.dll`.
295 // We don't know which, so let's assume that if our `path` above
296 // ends in `$target` we *could* be in the target libdir, and always
297 // assume that we may be in the main libdir.
298 sysroot_candidates
.push(path
.to_owned());
300 if path
.ends_with(target
) {
301 sysroot_candidates
.extend(
302 path
.parent() // chop off `$target`
303 .and_then(|p
| p
.parent()) // chop off `rustlib`
304 .and_then(|p
| p
.parent()) // chop off `lib`
305 .map(|s
| s
.to_owned()),
311 return sysroot_candidates
;
314 fn current_dll_path() -> Option
<PathBuf
> {
315 use std
::ffi
::{CStr, OsStr}
;
316 use std
::os
::unix
::prelude
::*;
319 let addr
= current_dll_path
as usize as *mut _
;
320 let mut info
= mem
::zeroed();
321 if libc
::dladdr(addr
, &mut info
) == 0 {
322 info
!("dladdr failed");
325 if info
.dli_fname
.is_null() {
326 info
!("dladdr returned null pointer");
329 let bytes
= CStr
::from_ptr(info
.dli_fname
).to_bytes();
330 let os
= OsStr
::from_bytes(bytes
);
331 Some(PathBuf
::from(os
))
336 fn current_dll_path() -> Option
<PathBuf
> {
337 use std
::ffi
::OsString
;
338 use std
::os
::windows
::prelude
::*;
341 use winapi
::um
::libloaderapi
::{
342 GetModuleFileNameW
, GetModuleHandleExW
, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
346 let mut module
= ptr
::null_mut();
347 let r
= GetModuleHandleExW(
348 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
349 current_dll_path
as usize as *mut _
,
353 info
!("GetModuleHandleExW failed: {}", io
::Error
::last_os_error());
356 let mut space
= Vec
::with_capacity(1024);
357 let r
= GetModuleFileNameW(module
, space
.as_mut_ptr(), space
.capacity() as u32);
359 info
!("GetModuleFileNameW failed: {}", io
::Error
::last_os_error());
363 if r
>= space
.capacity() {
364 info
!("our buffer was too small? {}", io
::Error
::last_os_error());
368 let os
= OsString
::from_wide(&space
);
369 Some(PathBuf
::from(os
))
374 pub fn get_builtin_codegen_backend(backend_name
: &str) -> fn() -> Box
<dyn CodegenBackend
> {
375 #[cfg(feature = "llvm")]
377 if backend_name
== "llvm" {
378 return rustc_codegen_llvm
::LlvmCodegenBackend
::new
;
382 let err
= format
!("unsupported builtin codegen backend `{}`", backend_name
);
383 early_error(ErrorOutputType
::default(), &err
);
386 pub(crate) fn compute_crate_disambiguator(session
: &Session
) -> CrateDisambiguator
{
387 use std
::hash
::Hasher
;
389 // The crate_disambiguator is a 128 bit hash. The disambiguator is fed
390 // into various other hashes quite a bit (symbol hashes, incr. comp. hashes,
391 // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits
392 // should still be safe enough to avoid collisions in practice.
393 let mut hasher
= StableHasher
::new();
395 let mut metadata
= session
.opts
.cg
.metadata
.clone();
396 // We don't want the crate_disambiguator to dependent on the order
397 // -C metadata arguments, so sort them:
399 // Every distinct -C metadata value is only incorporated once:
402 hasher
.write(b
"metadata");
404 // Also incorporate the length of a metadata string, so that we generate
405 // different values for `-Cmetadata=ab -Cmetadata=c` and
406 // `-Cmetadata=a -Cmetadata=bc`
407 hasher
.write_usize(s
.len());
408 hasher
.write(s
.as_bytes());
411 // Also incorporate crate type, so that we don't get symbol conflicts when
412 // linking against a library of the same name, if this is an executable.
413 let is_exe
= session
.crate_types().contains(&CrateType
::Executable
);
414 hasher
.write(if is_exe { b"exe" }
else { b"lib" }
);
416 CrateDisambiguator
::from(hasher
.finish
::<Fingerprint
>())
419 pub(crate) fn check_attr_crate_type(attrs
: &[ast
::Attribute
], lint_buffer
: &mut LintBuffer
) {
420 // Unconditionally collect crate types from attributes to make them used
421 for a
in attrs
.iter() {
422 if a
.check_name(sym
::crate_type
) {
423 if let Some(n
) = a
.value_str() {
424 if categorize_crate_type(n
).is_some() {
428 if let ast
::MetaItemKind
::NameValue(spanned
) = a
.meta().unwrap().kind
{
429 let span
= spanned
.span
;
430 let lev_candidate
= find_best_match_for_name(
431 CRATE_TYPES
.iter().map(|(k
, _
)| k
),
435 if let Some(candidate
) = lev_candidate
{
436 lint_buffer
.buffer_lint_with_diagnostic(
437 lint
::builtin
::UNKNOWN_CRATE_TYPES
,
440 "invalid `crate_type` value",
441 BuiltinLintDiagnostics
::UnknownCrateTypes(
443 "did you mean".to_string(),
444 format
!("\"{}\"", candidate
),
448 lint_buffer
.buffer_lint(
449 lint
::builtin
::UNKNOWN_CRATE_TYPES
,
452 "invalid `crate_type` value",
461 const CRATE_TYPES
: &[(Symbol
, CrateType
)] = &[
462 (sym
::rlib
, CrateType
::Rlib
),
463 (sym
::dylib
, CrateType
::Dylib
),
464 (sym
::cdylib
, CrateType
::Cdylib
),
465 (sym
::lib
, config
::default_lib_output()),
466 (sym
::staticlib
, CrateType
::Staticlib
),
467 (sym
::proc_dash_macro
, CrateType
::ProcMacro
),
468 (sym
::bin
, CrateType
::Executable
),
471 fn categorize_crate_type(s
: Symbol
) -> Option
<CrateType
> {
472 Some(CRATE_TYPES
.iter().find(|(key
, _
)| *key
== s
)?
.1)
475 pub fn collect_crate_types(session
: &Session
, attrs
: &[ast
::Attribute
]) -> Vec
<CrateType
> {
476 // Unconditionally collect crate types from attributes to make them used
477 let attr_types
: Vec
<CrateType
> = attrs
480 if a
.check_name(sym
::crate_type
) {
481 match a
.value_str() {
482 Some(s
) => categorize_crate_type(s
),
491 // If we're generating a test executable, then ignore all other output
492 // styles at all other locations
493 if session
.opts
.test
{
494 return vec
![CrateType
::Executable
];
497 // Only check command line flags if present. If no types are specified by
498 // command line, then reuse the empty `base` Vec to hold the types that
499 // will be found in crate attributes.
500 let mut base
= session
.opts
.crate_types
.clone();
502 base
.extend(attr_types
);
504 base
.push(output
::default_output_for_target(session
));
511 base
.retain(|crate_type
| {
512 let res
= !output
::invalid_output_for_target(session
, *crate_type
);
515 session
.warn(&format
!(
516 "dropping unsupported crate type `{}` for target `{}`",
517 *crate_type
, session
.opts
.target_triple
527 pub fn build_output_filenames(
529 odir
: &Option
<PathBuf
>,
530 ofile
: &Option
<PathBuf
>,
531 attrs
: &[ast
::Attribute
],
533 ) -> OutputFilenames
{
536 // "-" as input file will cause the parser to read from stdin so we
537 // have to make up a name
538 // We want to toss everything after the final '.'
539 let dirpath
= (*odir
).as_ref().cloned().unwrap_or_default();
541 // If a crate name is present, we use it as the link name
546 .or_else(|| rustc_attr
::find_crate_name(attrs
).map(|n
| n
.to_string()))
547 .unwrap_or_else(|| input
.filestem().to_owned());
549 OutputFilenames
::new(
553 sess
.opts
.cg
.extra_filename
.clone(),
554 sess
.opts
.output_types
.clone(),
558 Some(ref out_file
) => {
559 let unnamed_output_types
=
560 sess
.opts
.output_types
.values().filter(|a
| a
.is_none()).count();
561 let ofile
= if unnamed_output_types
> 1 {
563 "due to multiple output types requested, the explicitly specified \
564 output file name will be adapted for each output type",
568 if !sess
.opts
.cg
.extra_filename
.is_empty() {
569 sess
.warn("ignoring -C extra-filename flag due to -o flag");
571 Some(out_file
.clone())
574 sess
.warn("ignoring --out-dir flag due to -o flag");
577 OutputFilenames
::new(
578 out_file
.parent().unwrap_or_else(|| Path
::new("")).to_path_buf(),
579 out_file
.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
581 sess
.opts
.cg
.extra_filename
.clone(),
582 sess
.opts
.output_types
.clone(),
588 // Note: Also used by librustdoc, see PR #43348. Consider moving this struct elsewhere.
590 // FIXME: Currently the `everybody_loops` transformation is not applied to:
591 // * `const fn`, due to issue #43636 that `loop` is not supported for const evaluation. We are
592 // waiting for miri to fix that.
593 // * `impl Trait`, due to issue #43869 that functions returning impl Trait cannot be diverging.
594 // Solving this may require `!` to implement every trait, which relies on the an even more
595 // ambitious form of the closed RFC #1637. See also [#34511].
597 // [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401
598 pub struct ReplaceBodyWithLoop
<'a
, 'b
> {
599 within_static_or_const
: bool
,
600 nested_blocks
: Option
<Vec
<ast
::Block
>>,
601 resolver
: &'a
mut Resolver
<'b
>,
604 impl<'a
, 'b
> ReplaceBodyWithLoop
<'a
, 'b
> {
605 pub fn new(resolver
: &'a
mut Resolver
<'b
>) -> ReplaceBodyWithLoop
<'a
, 'b
> {
606 ReplaceBodyWithLoop { within_static_or_const: false, nested_blocks: None, resolver }
609 fn run
<R
, F
: FnOnce(&mut Self) -> R
>(&mut self, is_const
: bool
, action
: F
) -> R
{
610 let old_const
= mem
::replace(&mut self.within_static_or_const
, is_const
);
611 let old_blocks
= self.nested_blocks
.take();
612 let ret
= action(self);
613 self.within_static_or_const
= old_const
;
614 self.nested_blocks
= old_blocks
;
618 fn should_ignore_fn(ret_ty
: &ast
::FnRetTy
) -> bool
{
619 if let ast
::FnRetTy
::Ty(ref ty
) = ret_ty
{
620 fn involves_impl_trait(ty
: &ast
::Ty
) -> bool
{
622 ast
::TyKind
::ImplTrait(..) => true,
623 ast
::TyKind
::Slice(ref subty
)
624 | ast
::TyKind
::Array(ref subty
, _
)
625 | ast
::TyKind
::Ptr(ast
::MutTy { ty: ref subty, .. }
)
626 | ast
::TyKind
::Rptr(_
, ast
::MutTy { ty: ref subty, .. }
)
627 | ast
::TyKind
::Paren(ref subty
) => involves_impl_trait(subty
),
628 ast
::TyKind
::Tup(ref tys
) => any_involves_impl_trait(tys
.iter()),
629 ast
::TyKind
::Path(_
, ref path
) => {
630 path
.segments
.iter().any(|seg
| match seg
.args
.as_deref() {
632 Some(&ast
::GenericArgs
::AngleBracketed(ref data
)) => {
633 data
.args
.iter().any(|arg
| match arg
{
634 ast
::AngleBracketedArg
::Arg(arg
) => match arg
{
635 ast
::GenericArg
::Type(ty
) => involves_impl_trait(ty
),
636 ast
::GenericArg
::Lifetime(_
)
637 | ast
::GenericArg
::Const(_
) => false,
639 ast
::AngleBracketedArg
::Constraint(c
) => match c
.kind
{
640 ast
::AssocTyConstraintKind
::Bound { .. }
=> true,
641 ast
::AssocTyConstraintKind
::Equality { ref ty }
=> {
642 involves_impl_trait(ty
)
647 Some(&ast
::GenericArgs
::Parenthesized(ref data
)) => {
648 any_involves_impl_trait(data
.inputs
.iter())
649 || ReplaceBodyWithLoop
::should_ignore_fn(&data
.output
)
657 fn any_involves_impl_trait
<'a
, I
: Iterator
<Item
= &'a P
<ast
::Ty
>>>(mut it
: I
) -> bool
{
658 it
.any(|subty
| involves_impl_trait(subty
))
661 involves_impl_trait(ty
)
667 fn is_sig_const(sig
: &ast
::FnSig
) -> bool
{
668 matches
!(sig
.header
.constness
, ast
::Const
::Yes(_
))
669 || ReplaceBodyWithLoop
::should_ignore_fn(&sig
.decl
.output
)
673 impl<'a
> MutVisitor
for ReplaceBodyWithLoop
<'a
, '_
> {
674 fn visit_item_kind(&mut self, i
: &mut ast
::ItemKind
) {
675 let is_const
= match i
{
676 ast
::ItemKind
::Static(..) | ast
::ItemKind
::Const(..) => true,
677 ast
::ItemKind
::Fn(_
, ref sig
, _
, _
) => Self::is_sig_const(sig
),
680 self.run(is_const
, |s
| noop_visit_item_kind(i
, s
))
683 fn flat_map_trait_item(&mut self, i
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
684 let is_const
= match i
.kind
{
685 ast
::AssocItemKind
::Const(..) => true,
686 ast
::AssocItemKind
::Fn(_
, ref sig
, _
, _
) => Self::is_sig_const(sig
),
689 self.run(is_const
, |s
| noop_flat_map_assoc_item(i
, s
))
692 fn flat_map_impl_item(&mut self, i
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
693 self.flat_map_trait_item(i
)
696 fn visit_anon_const(&mut self, c
: &mut ast
::AnonConst
) {
697 self.run(true, |s
| noop_visit_anon_const(c
, s
))
700 fn visit_block(&mut self, b
: &mut P
<ast
::Block
>) {
702 rules
: ast
::BlockCheckMode
,
703 s
: Option
<ast
::Stmt
>,
704 resolver
: &mut Resolver
<'_
>,
707 stmts
: s
.into_iter().collect(),
709 id
: resolver
.next_node_id(),
710 span
: rustc_span
::DUMMY_SP
,
714 fn block_to_stmt(b
: ast
::Block
, resolver
: &mut Resolver
<'_
>) -> ast
::Stmt
{
715 let expr
= P(ast
::Expr
{
716 id
: resolver
.next_node_id(),
717 kind
: ast
::ExprKind
::Block(P(b
), None
),
718 span
: rustc_span
::DUMMY_SP
,
719 attrs
: AttrVec
::new(),
724 id
: resolver
.next_node_id(),
725 kind
: ast
::StmtKind
::Expr(expr
),
726 span
: rustc_span
::DUMMY_SP
,
730 let empty_block
= stmt_to_block(BlockCheckMode
::Default
, None
, self.resolver
);
731 let loop_expr
= P(ast
::Expr
{
732 kind
: ast
::ExprKind
::Loop(P(empty_block
), None
),
733 id
: self.resolver
.next_node_id(),
734 span
: rustc_span
::DUMMY_SP
,
735 attrs
: AttrVec
::new(),
739 let loop_stmt
= ast
::Stmt
{
740 id
: self.resolver
.next_node_id(),
741 span
: rustc_span
::DUMMY_SP
,
742 kind
: ast
::StmtKind
::Expr(loop_expr
),
745 if self.within_static_or_const
{
746 noop_visit_block(b
, self)
748 visit_clobber(b
.deref_mut(), |b
| {
749 let mut stmts
= vec
![];
751 let old_blocks
= self.nested_blocks
.replace(vec
![]);
753 stmts
.extend(self.flat_map_stmt(s
).into_iter().filter(|s
| s
.is_item()));
755 // we put a Some in there earlier with that replace(), so this is valid
756 let new_blocks
= self.nested_blocks
.take().unwrap();
757 self.nested_blocks
= old_blocks
;
758 stmts
.extend(new_blocks
.into_iter().map(|b
| block_to_stmt(b
, self.resolver
)));
761 let mut new_block
= ast
::Block { stmts, ..b }
;
763 if let Some(old_blocks
) = self.nested_blocks
.as_mut() {
764 //push our fresh block onto the cache and yield an empty block with `loop {}`
765 if !new_block
.stmts
.is_empty() {
766 old_blocks
.push(new_block
);
769 stmt_to_block(b
.rules
, Some(loop_stmt
), &mut self.resolver
)
771 //push `loop {}` onto the end of our fresh block and yield that
772 new_block
.stmts
.push(loop_stmt
);
780 // in general the pretty printer processes unexpanded code, so
781 // we override the default `visit_mac` method which panics.
782 fn visit_mac(&mut self, mac
: &mut ast
::MacCall
) {
783 noop_visit_mac(mac
, self)