Remove mono item collection strategy override from -Zprint-mono-items

Previously `-Zprint-mono-items` would override the mono item collection
strategy. When debugging one doesn't want to change the behaviour, so
this was counter productive. Additionally, the produced behaviour was
artificial and might never arise without using the option in the first
place (`-Zprint-mono-items=eager` without `-Clink-dead-code`).  Finally,
the option was incorrectly marked as `UNTRACKED`.

Resolve those issues, by turning `-Zprint-mono-items` into a boolean
flag that prints results of mono item collection without changing the
behaviour of mono item collection.

For codegen-units test incorporate `-Zprint-mono-items` flag directly
into compiletest tool.

Test changes are mechanical. `-Zprint-mono-items=lazy` was removed
without additional changes, and `-Zprint-mono-items=eager` was turned
into `-Clink-dead-code`.  Linking dead code disables internalization, so
tests have been updated accordingly.
This commit is contained in:
Tomasz Miąsko 2025-05-09 10:36:07 +02:00
parent c8b7f32434
commit 8c8225afe8
53 changed files with 74 additions and 111 deletions

View file

@ -720,7 +720,7 @@ fn test_unstable_options_tracking_hash() {
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
untracked!(print_codegen_stats, true);
untracked!(print_llvm_passes, true);
untracked!(print_mono_items, Some(String::from("abc")));
untracked!(print_mono_items, true);
untracked!(print_type_sizes, true);
untracked!(proc_macro_backtrace, true);
untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);

View file

@ -60,9 +60,6 @@ monomorphize_start_not_found = using `fn main` requires the standard library
monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
monomorphize_unknown_cgu_collection_mode =
unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
monomorphize_wasm_c_abi_transition =
this function {$is_call ->
[true] call

View file

@ -64,12 +64,6 @@ pub(crate) struct EncounteredErrorWhileInstantiating {
#[help]
pub(crate) struct StartNotFound;
#[derive(Diagnostic)]
#[diag(monomorphize_unknown_cgu_collection_mode)]
pub(crate) struct UnknownCguCollectionMode<'a> {
pub mode: &'a str,
}
#[derive(Diagnostic)]
#[diag(monomorphize_abi_error_disabled_vector_type)]
#[help]

View file

@ -124,7 +124,7 @@ use rustc_target::spec::SymbolVisibility;
use tracing::debug;
use crate::collector::{self, MonoItemCollectionStrategy, UsageMap};
use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode};
use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined};
struct PartitioningCx<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
@ -1127,27 +1127,10 @@ where
}
fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitions<'_> {
let collection_strategy = match tcx.sess.opts.unstable_opts.print_mono_items {
Some(ref s) => {
let mode = s.to_lowercase();
let mode = mode.trim();
if mode == "eager" {
MonoItemCollectionStrategy::Eager
} else {
if mode != "lazy" {
tcx.dcx().emit_warn(UnknownCguCollectionMode { mode });
}
MonoItemCollectionStrategy::Lazy
}
}
None => {
if tcx.sess.link_dead_code() {
MonoItemCollectionStrategy::Eager
} else {
MonoItemCollectionStrategy::Lazy
}
}
let collection_strategy = if tcx.sess.link_dead_code() {
MonoItemCollectionStrategy::Eager
} else {
MonoItemCollectionStrategy::Lazy
};
let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_strategy);
@ -1209,7 +1192,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio
}
}
if tcx.sess.opts.unstable_opts.print_mono_items.is_some() {
if tcx.sess.opts.unstable_opts.print_mono_items {
let mut item_to_cgus: UnordMap<_, Vec<_>> = Default::default();
for cgu in codegen_units {

View file

@ -2408,10 +2408,8 @@ options! {
"print codegen statistics (default: no)"),
print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
"print the LLVM optimization passes being run (default: no)"),
print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
"print the result of the monomorphization collection pass. \
Value `lazy` means to use normal collection; `eager` means to collect all items.
Note that this overwrites the effect `-Clink-dead-code` has on collection!"),
print_mono_items: bool = (false, parse_bool, [UNTRACKED],
"print the result of the monomorphization collection pass (default: no)"),
print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
"print layout information for each type encountered (default: no)"),
proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],

View file

@ -325,12 +325,8 @@ The tests in [`tests/codegen-units`] test the
[monomorphization](../backend/monomorph.md) collector and CGU partitioning.
These tests work by running `rustc` with a flag to print the result of the
monomorphization collection pass, and then special annotations in the file are
used to compare against that.
Each test should be annotated with the `//@
compile-flags:-Zprint-mono-items=VAL` directive with the appropriate `VAL` to
instruct `rustc` to print the monomorphization information.
monomorphization collection pass, i.e., `-Zprint-mono-items`, and then special
annotations in the file are used to compare against that.
Then, the test should be annotated with comments of the form `//~ MONO_ITEM
name` where `name` is the monomorphized string printed by rustc like `fn <u32 as

View file

@ -1583,7 +1583,10 @@ impl<'test> TestCx<'test> {
Crashes => {
set_mir_dump_dir(&mut rustc);
}
Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | RustdocJs => {
CodegenUnits => {
rustc.arg("-Zprint-mono-items");
}
Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | RustdocJs => {
// do not use JSON output
}
}

View file

@ -1,5 +1,5 @@
//@ needs-asm-support
//@ compile-flags: -Ccodegen-units=1 -Zprint-mono-items=lazy --crate-type=lib
//@ compile-flags: -Ccodegen-units=1 --crate-type=lib
#[inline(always)]
pub unsafe fn f() {

View file

@ -1,5 +1,5 @@
//@ edition: 2021
//@ compile-flags: -Zprint-mono-items=eager --crate-type=lib
//@ compile-flags: -Clink-dead-code --crate-type=lib
//~ MONO_ITEM fn async_fn @@
//~ MONO_ITEM fn async_fn::{closure#0} @@

View file

@ -1,6 +1,6 @@
// We need to disable MIR inlining in both this and its aux-build crate. The MIR inliner
// will just inline everything into our start function if we let it. As it should.
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![no_main]
@ -11,12 +11,12 @@ extern crate cgu_extern_closures;
//~ MONO_ITEM fn main @@ cross_crate_closures-cgu.0[External]
#[no_mangle]
extern "C" fn main(_: core::ffi::c_int, _: *const *const u8) -> core::ffi::c_int {
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[Internal]
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[External]
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[External]
let _ = cgu_extern_closures::inlined_fn(1, 2);
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::<i32> @@ cross_crate_closures-cgu.0[Internal]
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::<i32>::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::<i32> @@ cross_crate_closures-cgu.0[External]
//~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::<i32>::{closure#0} @@ cross_crate_closures-cgu.0[External]
let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32);
// Nothing should be generated for this call, we just link to the instance

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no -Copt-level=0
//@ compile-flags:-Clink-dead-code -Zinline-mir=no -Copt-level=0
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,6 +1,6 @@
// Ensure that we *eagerly* monomorphize drop instances for structs with lifetimes.
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
//@ compile-flags:--crate-type=lib
//~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop> - shim(Some(StructWithDrop))

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
//@ compile-flags:-Zinline-mir=no
//@ compile-flags: -O

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
//@ compile-flags: -O
#![deny(dead_code)]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,5 +1,3 @@
//@ compile-flags:-Zprint-mono-items=lazy
// rust-lang/rust#90405
// Ensure implicit panic calls are collected

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zmir-opt-level=0
//@ compile-flags:-Clink-dead-code -Zmir-opt-level=0
#![deny(dead_code)]
#![crate_type = "lib"]
@ -24,7 +24,7 @@ impl<T> Trait for Struct<T> {
pub fn start(_: isize, _: *const *const u8) -> isize {
let s1 = Struct { _a: 0u32 };
//~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u32>> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
//~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u32>> - shim(None) @@ instantiation_through_vtable-cgu.0[External]
//~ MONO_ITEM fn <Struct<u32> as Trait>::foo
//~ MONO_ITEM fn <Struct<u32> as Trait>::bar
let r1 = &s1 as &Trait;
@ -32,7 +32,7 @@ pub fn start(_: isize, _: *const *const u8) -> isize {
r1.bar();
let s1 = Struct { _a: 0u64 };
//~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u64>> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
//~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u64>> - shim(None) @@ instantiation_through_vtable-cgu.0[External]
//~ MONO_ITEM fn <Struct<u64> as Trait>::foo
//~ MONO_ITEM fn <Struct<u64> as Trait>::bar
let _ = &s1 as &Trait;

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Copt-level=0
//@ compile-flags:-Clink-dead-code -Copt-level=0
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,17 +1,17 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![crate_type = "lib"]
//~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[External]
fn temporary() {
//~ MONO_ITEM fn temporary::{closure#0} @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn temporary::{closure#0} @@ non_generic_closures-cgu.0[External]
(|a: u32| {
let _ = a;
})(4);
}
//~ MONO_ITEM fn assigned_to_variable_but_not_executed @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn assigned_to_variable_but_not_executed @@ non_generic_closures-cgu.0[External]
fn assigned_to_variable_but_not_executed() {
//~ MONO_ITEM fn assigned_to_variable_but_not_executed::{closure#0}
let _x = |a: i16| {
@ -19,21 +19,21 @@ fn assigned_to_variable_but_not_executed() {
};
}
//~ MONO_ITEM fn assigned_to_variable_executed_indirectly @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn assigned_to_variable_executed_indirectly @@ non_generic_closures-cgu.0[External]
fn assigned_to_variable_executed_indirectly() {
//~ MONO_ITEM fn assigned_to_variable_executed_indirectly::{closure#0} @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim(vtable) @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn std::ptr::drop_in_place::<{closure@TEST_PATH:28:13: 28:21}> - shim(None) @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn assigned_to_variable_executed_indirectly::{closure#0} @@ non_generic_closures-cgu.0[External]
//~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim @@ non_generic_closures-cgu.0[External]
//~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim(vtable) @@ non_generic_closures-cgu.0[External]
//~ MONO_ITEM fn std::ptr::drop_in_place::<{closure@TEST_PATH:28:13: 28:21}> - shim(None) @@ non_generic_closures-cgu.0[External]
let f = |a: i32| {
let _ = a + 2;
};
run_closure(&f);
}
//~ MONO_ITEM fn assigned_to_variable_executed_directly @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn assigned_to_variable_executed_directly @@ non_generic_closures-cgu.0[External]
fn assigned_to_variable_executed_directly() {
//~ MONO_ITEM fn assigned_to_variable_executed_directly::{closure#0} @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn assigned_to_variable_executed_directly::{closure#0} @@ non_generic_closures-cgu.0[External]
let f = |a: i64| {
let _ = a + 3;
};
@ -51,7 +51,7 @@ pub fn start(_: isize, _: *const *const u8) -> isize {
0
}
//~ MONO_ITEM fn run_closure @@ non_generic_closures-cgu.0[Internal]
//~ MONO_ITEM fn run_closure @@ non_generic_closures-cgu.0[External]
fn run_closure(f: &Fn(i32)) {
f(3);
}

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
//@ compile-flags: -O
#![deny(dead_code)]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
//@ compile-flags:-Clink-dead-code -Zinline-mir=no
#![deny(dead_code)]
#![crate_type = "lib"]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
//@ compile-flags: -O
#![deny(dead_code)]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
//@ compile-flags: -O
#![deny(dead_code)]

View file

@ -1,5 +1,3 @@
//@ compile-flags:-Zprint-mono-items=lazy
#![deny(dead_code)]
#![crate_type = "rlib"]

View file

@ -1,5 +1,3 @@
//@ compile-flags:-Zprint-mono-items=lazy
// N.B., we do not expect *any* monomorphization to be generated here.
#![deny(dead_code)]

View file

@ -1,4 +1,3 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Zmir-opt-level=0
#![deny(dead_code)]

View file

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager
//@ compile-flags:-Clink-dead-code
#![crate_type = "lib"]
#![deny(dead_code)]

View file

@ -3,11 +3,10 @@
This test suite is designed to test that codegen unit partitioning works as intended.
Note that it does not evaluate whether CGU partitioning is *good*. That is the job of the compiler benchmark suite.
All tests in this suite use the flag `-Zprint-mono-items=lazy`, which makes the compiler print a machine-readable summary of all MonoItems that were collected, which CGUs they were assigned to, and the linkage in each CGU. The output looks like:
All tests in this suite use the flag `-Zprint-mono-items`, which makes the compiler print a machine-readable summary of all MonoItems that were collected, which CGUs they were assigned to, and the linkage in each CGU. The output looks like:
```
MONO_ITEM <item> @@ <cgu name>[<linkage>] <other cgu name>[<linkage in other cgu>]
```
DO NOT add tests to this suite that use `-Zprint-mono-items=eager`. That flag changes the way that MonoItem collection works in rather fundamental ways that are otherwise only used by `-Clink-dead-code`, and thus the MonoItems collected and their linkage under `-Zprint-mono-items=eager` does not correlate very well with normal compilation behavior.
The current CGU partitioning algorithm essentially groups MonoItems by which module they are defined in, then merges small CGUs. There are a lot of inline modules in this test suite because that's the only way to observe the partitioning.

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "rlib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "lib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -Ccodegen-units=3
//@ compile-flags: -Copt-level=0 -Ccodegen-units=3
#![crate_type = "rlib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "lib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=1
//@ compile-flags: -Copt-level=1
#![crate_type = "lib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "rlib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "lib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "rlib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "lib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "lib"]

View file

@ -2,7 +2,7 @@
// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels
// prevent drop-glue from participating in share-generics.
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Zshare-generics=yes -Copt-level=0
//@ compile-flags: -Zshare-generics=yes -Copt-level=0
#![crate_type = "rlib"]

View file

@ -1,5 +1,5 @@
//@ incremental
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "rlib"]

View file

@ -1,6 +1,6 @@
//@ incremental
// Need to disable optimizations to ensure consistent output across all CI runners.
//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
//@ compile-flags: -Copt-level=0
#![crate_type = "rlib"]

View file

@ -1,5 +1,5 @@
//@ known-bug: #114198
//@ compile-flags: -Zprint-mono-items=eager
//@ compile-flags: -Zprint-mono-items -Clink-dead-code
impl Trait for <Ty as Owner>::Struct {}
trait Trait {

View file

@ -1,5 +1,5 @@
//@ known-bug: #114198
//@ compile-flags: -Zprint-mono-items=eager
//@ compile-flags: -Zprint-mono-items -Clink-dead-code
#![feature(lazy_type_alias)]