Skip to content
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

[experiment] Add -Z no-link flag #67195

Merged
merged 1 commit into from
Jan 23, 2020
Merged

[experiment] Add -Z no-link flag #67195

merged 1 commit into from
Jan 23, 2020

Conversation

0dvictor
Copy link
Contributor

@0dvictor 0dvictor commented Dec 10, 2019

Adds a compiler option to allow rustc compile a crate without linking.
With this flag, rustc serializes codegen_results into a .rlink file.

Part of Issue #64191

@rust-highfive
Copy link
Collaborator

r? @matthewjasper

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 10, 2019
@0dvictor 0dvictor changed the title Add -Z no-link flag [experiment] Add -Z no-link flag Dec 10, 2019
@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-7 of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2019-12-10T12:35:15.6609777Z ##[command]git remote add origin https://github.com/rust-lang/rust
2019-12-10T12:35:15.6817518Z ##[command]git config gc.auto 0
2019-12-10T12:35:16.2452065Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2019-12-10T12:35:16.2457204Z ##[command]git config --get-all http.proxy
2019-12-10T12:35:16.2463412Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/67195/merge:refs/remotes/pull/67195/merge
---
2019-12-10T12:41:09.8847172Z    Compiling serde_json v1.0.40
2019-12-10T12:41:11.6221690Z    Compiling tidy v0.1.0 (/checkout/src/tools/tidy)
2019-12-10T12:41:22.6207840Z     Finished release [optimized] target(s) in 1m 28s
2019-12-10T12:41:22.6322224Z tidy check
2019-12-10T12:41:23.4268625Z tidy error: /checkout/src/librustc_session/config.rs: too many lines (3015) (add `// ignore-tidy-filelength` to the file to suppress this error)
2019-12-10T12:41:25.3800276Z some tidy checks failed
2019-12-10T12:41:25.3803694Z Found 485 error codes
2019-12-10T12:41:25.3804509Z Found 0 error codes with no tests
2019-12-10T12:41:25.3804796Z Done!
2019-12-10T12:41:25.3804796Z Done!
2019-12-10T12:41:25.3805117Z 
2019-12-10T12:41:25.3805345Z 
2019-12-10T12:41:25.3806701Z command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor"
2019-12-10T12:41:25.3809219Z 
2019-12-10T12:41:25.3809446Z 
2019-12-10T12:41:25.3809791Z failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test src/tools/tidy
2019-12-10T12:41:25.3810052Z Build completed unsuccessfully in 0:01:32
2019-12-10T12:41:25.3810052Z Build completed unsuccessfully in 0:01:32
2019-12-10T12:41:25.3864524Z == clock drift check ==
2019-12-10T12:41:25.3872832Z   local time: Tue Dec 10 12:41:25 UTC 2019
2019-12-10T12:41:25.5375810Z   network time: Tue, 10 Dec 2019 12:41:25 GMT
2019-12-10T12:41:25.5378009Z == end clock drift check ==
2019-12-10T12:41:26.8769521Z 
2019-12-10T12:41:26.8887665Z ##[error]Bash exited with code '1'.
2019-12-10T12:41:26.8924335Z ##[section]Starting: Checkout
2019-12-10T12:41:26.8926199Z ==============================================================================
2019-12-10T12:41:26.8926260Z Task         : Get sources
2019-12-10T12:41:26.8926311Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@@ -933,6 +933,10 @@ fn encode_and_write_metadata(
}).max().unwrap_or(MetadataKind::None);

let metadata = match metadata_kind {

// Metadata is always required for two-staged compile and link.
Copy link
Member

@bjorn3 bjorn3 Dec 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only necessary data is the data passed to https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_utils/codegen_backend/trait.CodegenBackend.html#tymethod.join_codegen_and_link:

  • Session
  • OutputFilenames
  • CodegenResults (Actually OngoingCodegen is passed, but when joining the codegen, CodegenResults is produced)

DepGraph is not necessary (it is used for storing the location of incremental compilation artifacts, https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_codegen_llvm/lib.rs.html#307 but after joining codegen, the no-link invocation of rustc can do this itself)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, metadata is for reconstructing CrateInfo (part of CodegenResult), as it need information about dependent libraries (both rlib and native ones).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be possible to just derive Serialize for CrateInfo and put it in a .rlink file together with the other necessary data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, let me look into it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found CrateInfo + "other necessary data" is indeed CodegenResults. So I updated my the PR to serialize CodegenResults into a .rlink file.

@@ -308,7 +308,8 @@ impl CodegenBackend for LlvmCodegenBackend {

sess.compile_status()?;

if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
if sess.opts.debugging_opts.no_link ||
!sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
i == OutputType::Metadata) {
return Ok(());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that finalize_session_directory is never called in this case, which means that incremental compilation won't work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it have been called for Exe and Metadata output types, too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current condition says return if neither exe, nor metadata is emitted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that codegen_backend.join_codegen_and_link needs to be called to actually emit all object files. Maybe split rename it to join_codegen and return CodegenResults from it, leaving the linker part to rustc_driver?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion. In fact, I think it is a good refactoring even without this -Z no-link change.

@tmandry
Copy link
Member

tmandry commented Dec 10, 2019

r? @tmandry
cc @alexcrichton

OutputType::Bitcode => {
modules_config.emit_bc = true;
if sess.opts.debugging_opts.no_link {
metadata_config.emit_bc = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be missing something here, but I don't really see why metadata codegen involves bitcode, LLVM IR, etc. This should only control the output of the rmeta file read by rustc if I'm not mistaken.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe -Zno-link should still compile everything, only leaving the linking to a next rustc invocation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This metadata_config isn't for the rmeta file used later for linking. It is to generate a metadata module linking into a Dylib or ProcMacro. Bitcode/LLVM IR/etc. won't be generated for any other crate types.

@tmandry
Copy link
Member

tmandry commented Dec 12, 2019

It.. looks like this change hit a file line length tidy limit (3000 lines) in src/librustc_session/config.rs.

This seems arbitrary, and it's a bit unfair for a new contributor to have to deal with this. Does anyone who's contributed to this file have suggestions on how to break it up? Or should we override it for now?

@Centril
Copy link
Contributor

Centril commented Dec 12, 2019

@tmandry The limit is arbitrary, but that's the fundamental nature of limits. :) I believe these tidy checks are necessary for code quality to push us towards reasonably sized files (not like parser.rs was before...).

I would suggest one of the following strategies:

  • Refactor the file before landing this PR and then rebase this one. (This is probably not super fun but perhaps @0dvictor wants to tackle it?)

  • Refactor the file after landing this PR and leave an override for now; file an issue to split it up and assign yourself to do it. It shouldn't take a long time to split up a file and reviewing it is just a matter of using diff to check that nothing really changed. Moving out fn build_session_options and friends seem like a prime candidate for splitting up. I'd also consider moving the data types + some impls out to its own module.

@0dvictor
Copy link
Contributor Author

I'm happy to refactor config.rs then rebase this PR. Briefly going through this file, I found it now contains two kinds of logic: 1. definition of CLI arguments, and 2. logics to parse and validate CLI arguments. So I'm thinking of moving following code out to a new file named options.rs:

  • // The top-level command-line options struct.
    //
    // For each option, one has to specify how it behaves with regard to the
    // dependency tracking system of incremental compilation. This is done via the
    // square-bracketed directive after the field type. The options are:
    //
    // [TRACKED]
    // A change in the given field will cause the compiler to completely clear the
    // incremental compilation cache before proceeding.
    //
    // [UNTRACKED]
    // Incremental compilation is not influenced by this option.
    //
    // If you add a new option to this struct or one of the sub-structs like
    // `CodegenOptions`, think about how it influences incremental compilation. If in
    // doubt, specify [TRACKED], which is always "correct" but might lead to
    // unnecessary re-compilation.
    top_level_options!(
    pub struct Options {
    // The crate config requested for the session, which may be combined
    // with additional crate configurations during the compile process.
    crate_types: Vec<CrateType> [TRACKED],
    optimize: OptLevel [TRACKED],
    // Include the `debug_assertions` flag in dependency tracking, since it
    // can influence whether overflow checks are done or not.
    debug_assertions: bool [TRACKED],
    debuginfo: DebugInfo [TRACKED],
    lint_opts: Vec<(String, lint::Level)> [TRACKED],
    lint_cap: Option<lint::Level> [TRACKED],
    describe_lints: bool [UNTRACKED],
    output_types: OutputTypes [TRACKED],
    search_paths: Vec<SearchPath> [UNTRACKED],
    libs: Vec<(String, Option<String>, Option<NativeLibraryKind>)> [TRACKED],
    maybe_sysroot: Option<PathBuf> [UNTRACKED],
    target_triple: TargetTriple [TRACKED],
    test: bool [TRACKED],
    error_format: ErrorOutputType [UNTRACKED],
    // If `Some`, enable incremental compilation, using the given
    // directory to store intermediate results.
    incremental: Option<PathBuf> [UNTRACKED],
    debugging_opts: DebuggingOptions [TRACKED],
    prints: Vec<PrintRequest> [UNTRACKED],
    // Determines which borrow checker(s) to run. This is the parsed, sanitized
    // version of `debugging_opts.borrowck`, which is just a plain string.
    borrowck_mode: BorrowckMode [UNTRACKED],
    cg: CodegenOptions [TRACKED],
    externs: Externs [UNTRACKED],
    crate_name: Option<String> [TRACKED],
    // An optional name to use as the crate for std during std injection,
    // written `extern crate name as std`. Defaults to `std`. Used by
    // out-of-tree drivers.
    alt_std_name: Option<String> [TRACKED],
    // Indicates how the compiler should treat unstable features.
    unstable_features: UnstableFeatures [TRACKED],
    // Indicates whether this run of the compiler is actually rustdoc. This
    // is currently just a hack and will be removed eventually, so please
    // try to not rely on this too much.
    actually_rustdoc: bool [TRACKED],
    // Specifications of codegen units / ThinLTO which are forced as a
    // result of parsing command line options. These are not necessarily
    // what rustc was invoked with, but massaged a bit to agree with
    // commands like `--emit llvm-ir` which they're often incompatible with
    // if we otherwise use the defaults of rustc.
    cli_forced_codegen_units: Option<usize> [UNTRACKED],
    cli_forced_thinlto_off: bool [UNTRACKED],
    // Remap source path prefixes in all output (messages, object files, debug, etc.).
    remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
    edition: Edition [TRACKED],
    // `true` if we're emitting JSON blobs about each artifact produced
    // by the compiler.
    json_artifact_notifications: bool [TRACKED],
    pretty: Option<PpMode> [UNTRACKED],
    }
    );
  • options! {CodegenOptions, CodegenSetter, basic_codegen_options,
    build_codegen_options, "C", "codegen",
    CG_OPTIONS, cg_type_desc, cgsetters,
    ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
    "this option is deprecated and does nothing"),
    linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
    "system linker to link outputs with"),
    link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
    "a single extra argument to append to the linker invocation (can be used several times)"),
    link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
    "extra arguments to append to the linker invocation (space separated)"),
    link_dead_code: bool = (false, parse_bool, [UNTRACKED],
    "don't let linker strip dead code (turning it on can be used for code coverage)"),
    lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
    "perform LLVM link-time optimizations"),
    target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
    "select target processor (`rustc --print target-cpus` for details)"),
    target_feature: String = (String::new(), parse_string, [TRACKED],
    "target specific attributes. (`rustc --print target-features` for details). \
    This feature is unsafe."),
    passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
    "a list of extra LLVM passes to run (space separated)"),
    llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
    "a list of arguments to pass to LLVM (space separated)"),
    save_temps: bool = (false, parse_bool, [UNTRACKED],
    "save all temporary output files during compilation"),
    rpath: bool = (false, parse_bool, [UNTRACKED],
    "set rpath values in libs/exes"),
    overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "use overflow checks for integer arithmetic"),
    no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
    "don't pre-populate the pass manager with a list of passes"),
    no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
    "don't run the loop vectorization optimization passes"),
    no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
    "don't run LLVM's SLP vectorization pass"),
    soft_float: bool = (false, parse_bool, [TRACKED],
    "use soft float ABI (*eabihf targets only)"),
    prefer_dynamic: bool = (false, parse_bool, [TRACKED],
    "prefer dynamic linking to static linking"),
    no_integrated_as: bool = (false, parse_bool, [TRACKED],
    "use an external assembler rather than LLVM's integrated one"),
    no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "disable the use of the redzone"),
    relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
    "choose the relocation model to use (`rustc --print relocation-models` for details)"),
    code_model: Option<String> = (None, parse_opt_string, [TRACKED],
    "choose the code model to use (`rustc --print code-models` for details)"),
    metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
    "metadata to mangle symbol names with"),
    extra_filename: String = (String::new(), parse_string, [UNTRACKED],
    "extra data to put in each output filename"),
    codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
    "divide crate into N units to optimize in parallel"),
    remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
    "print remarks for these optimization passes (space separated, or \"all\")"),
    no_stack_check: bool = (false, parse_bool, [UNTRACKED],
    "the `--no-stack-check` flag is deprecated and does nothing"),
    debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
    "debug info emission level, 0 = no debug info, 1 = line tables only, \
    2 = full debug info with variable and type information"),
    opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
    "optimize with possible levels 0-3, s, or z"),
    force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "force use of the frame pointers"),
    debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "explicitly enable the `cfg(debug_assertions)` directive"),
    inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
    "set the threshold for inlining a function (default: 225)"),
    panic: Option<PanicStrategy> = (None, parse_panic_strategy,
    [TRACKED], "panic strategy to compile crate with"),
    incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
    "enable incremental compilation"),
    default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
    "allow the linker to link its default libraries"),
    linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
    "linker flavor"),
    linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
    parse_linker_plugin_lto, [TRACKED],
    "generate build artifacts that are compatible with linker-based LTO."),
    profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
    parse_switch_with_opt_path, [TRACKED],
    "compile the program with profiling instrumentation"),
    profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
    "use the given `.profdata` file for profile-guided optimization"),
    }
    options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
    build_debugging_options, "Z", "debugging",
    DB_OPTIONS, db_type_desc, dbsetters,
    codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
    "the backend to use"),
    verbose: bool = (false, parse_bool, [UNTRACKED],
    "in general, enable more debug printouts"),
    span_free_formats: bool = (false, parse_bool, [UNTRACKED],
    "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
    identify_regions: bool = (false, parse_bool, [UNTRACKED],
    "make unnamed regions display as '# (where # is some non-ident unique id)"),
    borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
    "select which borrowck is used (`mir` or `migrate`)"),
    time_passes: bool = (false, parse_bool, [UNTRACKED],
    "measure time of each rustc pass"),
    time: bool = (false, parse_bool, [UNTRACKED],
    "measure time of rustc processes"),
    time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
    "measure time of each LLVM pass"),
    input_stats: bool = (false, parse_bool, [UNTRACKED],
    "gather statistics about the input"),
    asm_comments: bool = (false, parse_bool, [TRACKED],
    "generate comments into the assembly (may change behavior)"),
    verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
    "verify LLVM IR"),
    borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
    "gather borrowck statistics"),
    no_landing_pads: bool = (false, parse_bool, [TRACKED],
    "omit landing pads for unwinding"),
    fewer_names: bool = (false, parse_bool, [TRACKED],
    "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
    meta_stats: bool = (false, parse_bool, [UNTRACKED],
    "gather metadata statistics"),
    print_link_args: bool = (false, parse_bool, [UNTRACKED],
    "print the arguments passed to the linker"),
    print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
    "prints the LLVM optimization passes being run"),
    ast_json: bool = (false, parse_bool, [UNTRACKED],
    "print the AST as JSON and halt"),
    // We default to 1 here since we want to behave like
    // a sequential compiler for now. This'll likely be adjusted
    // in the future. Note that -Zthreads=0 is the way to get
    // the num_cpus behavior.
    threads: usize = (1, parse_threads, [UNTRACKED],
    "use a thread pool with N threads"),
    ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
    "print the pre-expansion AST as JSON and halt"),
    ls: bool = (false, parse_bool, [UNTRACKED],
    "list the symbols defined by a library crate"),
    save_analysis: bool = (false, parse_bool, [UNTRACKED],
    "write syntax and type analysis (in JSON format) information, in \
    addition to normal output"),
    print_region_graph: bool = (false, parse_bool, [UNTRACKED],
    "prints region inference graph. \
    Use with RUST_REGION_GRAPH=help for more info"),
    parse_only: bool = (false, parse_bool, [UNTRACKED],
    "parse only; do not compile, assemble, or link"),
    dual_proc_macros: bool = (false, parse_bool, [TRACKED],
    "load proc macros for both target and host, but only link to the target"),
    no_codegen: bool = (false, parse_bool, [TRACKED],
    "run all passes except codegen; no output"),
    treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
    "treat error number `val` that occurs as bug"),
    report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
    "immediately print bugs registered with `delay_span_bug`"),
    external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
    "show macro backtraces even for non-local macros"),
    teach: bool = (false, parse_bool, [TRACKED],
    "show extended diagnostic help"),
    terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
    "set the current terminal width"),
    panic_abort_tests: bool = (false, parse_bool, [TRACKED],
    "support compiling tests with panic=abort"),
    continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
    "attempt to recover from parse errors (experimental)"),
    dep_tasks: bool = (false, parse_bool, [UNTRACKED],
    "print tasks that execute and the color their dep node gets (requires debug build)"),
    incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
    "enable incremental compilation (experimental)"),
    incremental_queries: bool = (true, parse_bool, [UNTRACKED],
    "enable incremental compilation support for queries (experimental)"),
    incremental_info: bool = (false, parse_bool, [UNTRACKED],
    "print high-level information about incremental reuse (or the lack thereof)"),
    incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
    "dump hash information in textual format to stdout"),
    incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
    "verify incr. comp. hashes of green query instances"),
    incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
    "ignore spans during ICH computation -- used for testing"),
    instrument_mcount: bool = (false, parse_bool, [TRACKED],
    "insert function instrument code for mcount-based tracing"),
    dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
    "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
    query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
    "enable queries of the dependency graph for regression testing"),
    no_analysis: bool = (false, parse_bool, [UNTRACKED],
    "parse and expand the source, but run no analysis"),
    unstable_options: bool = (false, parse_bool, [UNTRACKED],
    "adds unstable command line options to rustc interface"),
    force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "force overflow checks on or off"),
    trace_macros: bool = (false, parse_bool, [UNTRACKED],
    "for every macro invocation, print its name and arguments"),
    debug_macros: bool = (false, parse_bool, [TRACKED],
    "emit line numbers debug info inside macros"),
    generate_arange_section: bool = (true, parse_bool, [TRACKED],
    "generate DWARF address ranges for faster lookups"),
    keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
    "don't clear the hygiene data after analysis"),
    keep_ast: bool = (false, parse_bool, [UNTRACKED],
    "keep the AST after lowering it to HIR"),
    show_span: Option<String> = (None, parse_opt_string, [TRACKED],
    "show spans for compiler debugging (expr|pat|ty)"),
    print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
    "print layout information for each type encountered"),
    print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
    "print the result of the monomorphization collection pass"),
    mir_opt_level: usize = (1, parse_uint, [TRACKED],
    "set the MIR optimization level (0-3, default: 1)"),
    mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "emit noalias metadata for mutable references (default: no)"),
    dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
    "dump MIR state to file.
    `val` is used to select which passes and functions to dump. For example:
    `all` matches all passes and functions,
    `foo` matches all passes for functions whose name contains 'foo',
    `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
    `foo | bar` all passes for function names containing 'foo' or 'bar'."),
    dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
    "the directory the MIR is dumped into"),
    dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
    "in addition to `.mir` files, create graphviz `.dot` files"),
    dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
    "if set, exclude the pass number when dumping MIR (used in tests)"),
    mir_emit_retag: bool = (false, parse_bool, [TRACKED],
    "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
    perf_stats: bool = (false, parse_bool, [UNTRACKED],
    "print some performance-related statistics"),
    query_stats: bool = (false, parse_bool, [UNTRACKED],
    "print some statistics about the query system"),
    hir_stats: bool = (false, parse_bool, [UNTRACKED],
    "print some statistics about AST and HIR"),
    always_encode_mir: bool = (false, parse_bool, [TRACKED],
    "encode MIR of all functions into the crate metadata"),
    json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
    "describes how to render the `rendered` field of json diagnostics"),
    unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
    "take the breaks off const evaluation. NOTE: this is unsound"),
    osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
    "pass `-install_name @rpath/...` to the macOS linker"),
    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
    "use a sanitizer"),
    sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
    "Enable recovery for selected sanitizers"),
    sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
    "Enable origins tracking in MemorySanitizer"),
    fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
    "set the optimization fuel quota for a crate"),
    print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
    "make rustc print the total optimization fuel used by a crate"),
    force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
    "force all crates to be `rustc_private` unstable"),
    pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
    "a single extra argument to prepend the linker invocation (can be used several times)"),
    pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
    "extra arguments to prepend to the linker invocation (space separated)"),
    profile: bool = (false, parse_bool, [TRACKED],
    "insert profiling code"),
    disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
    "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
    relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
    "choose which RELRO level to use"),
    nll_facts: bool = (false, parse_bool, [UNTRACKED],
    "dump facts from NLL analysis into side files"),
    nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
    "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
    dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
    "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
    polonius: bool = (false, parse_bool, [UNTRACKED],
    "enable polonius-based borrow-checker"),
    codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
    "generate a graphical HTML report of time spent in codegen and LLVM"),
    thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "enable ThinLTO when possible"),
    inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "control whether `#[inline]` functions are in all CGUs"),
    tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
    "choose the TLS model to use (`rustc --print tls-models` for details)"),
    saturating_float_casts: bool = (false, parse_bool, [TRACKED],
    "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
    the max/min integer respectively, and NaN is mapped to 0"),
    human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
    "generate human-readable, predictable names for codegen units"),
    dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
    "in dep-info output, omit targets for tracking dependencies of the dep-info files \
    themselves"),
    unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
    "present the input source, unstable (and less-pretty) variants;
    valid types are any of the types for `--pretty`, as well as:
    `expanded`, `expanded,identified`,
    `expanded,hygiene` (with internal representations),
    `everybody_loops` (all function bodies replaced with `loop {}`),
    `hir` (the HIR), `hir,identified`,
    `hir,typed` (HIR with types for each node),
    `hir-tree` (dump the raw HIR),
    `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
    run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "run `dsymutil` and delete intermediate object files"),
    ui_testing: bool = (false, parse_bool, [UNTRACKED],
    "format compiler diagnostics in a way that's better suitable for UI testing"),
    embed_bitcode: bool = (false, parse_bool, [TRACKED],
    "embed LLVM bitcode in object files"),
    strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "tell the linker to strip debuginfo when building without debuginfo enabled."),
    share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "make the current crate share its generic instantiations"),
    chalk: bool = (false, parse_bool, [TRACKED],
    "enable the experimental Chalk-based trait solving engine"),
    no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
    "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
    no_leak_check: bool = (false, parse_bool, [UNTRACKED],
    "disables the 'leak check' for subtyping; unsound, but useful for tests"),
    no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
    "don't interleave execution of lints; allows benchmarking individual lints"),
    crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
    "inject the given attribute in the crate"),
    self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
    parse_switch_with_opt_path, [UNTRACKED],
    "run the self profiler and output the raw event data"),
    self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
    "specifies which kinds of events get recorded by the self profiler"),
    emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
    "emits a section containing stack size metadata"),
    plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
    "whether to use the PLT when calling into shared libraries;
    only has effect for PIC code on systems with ELF binaries
    (default: PLT is disabled if full relro is enabled)"),
    merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
    "control the operation of the MergeFunctions LLVM pass, taking
    the same values as the target option of the same name"),
    allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
    "only allow the listed language features to be enabled in code (space separated)"),
    symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
    parse_symbol_mangling_version, [TRACKED],
    "which mangling version to use for symbol names"),
    binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
    "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
    insert_sideeffect: bool = (false, parse_bool, [TRACKED],
    "fix undefined behavior when a thread doesn't eventually make progress \
    (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
    }

On top of that, as @Centril suggested, I also would like to move fn build_session_options and friends into a new file named config_builder.rs.

What do you guys think, @tmandry and @Centril ?

@Centril
Copy link
Contributor

Centril commented Dec 12, 2019

What do you guys think, @tmandry and @Centril ?

Sounds like a sensible general direction. 👍

@tmandry
Copy link
Member

tmandry commented Dec 12, 2019

I don't personally love the idea of separating the primary data structure definition of Options from the code that builds it. I am fine with separating out the macros and validator helper functions. So I guess I would personally put both the things you're talking about splitting into the same file.

That said, just do what seems most reasonable for now and we can see how it looks in review. I don't want to get bogged down in a refactoring bikeshed 😄

@alexcrichton
Copy link
Member

It may be worth pointing out that simply the presence of --emit obj will force codegen units to 1, so if -Z no-link is tweaking the output types of the compiler it may have the side effect of pretty radically changing compilation by reducing the number of codegen units to 1 in all cases.

@0dvictor
Copy link
Contributor Author

// ignore-tidy-filelength was introduced by #67074 to config.rs, do we still want to refactor this file? @Centril @tmandry

@0dvictor
Copy link
Contributor Author

It may be worth pointing out that simply the presence of --emit obj will force codegen units to 1, so if -Z no-link is tweaking the output types of the compiler it may have the side effect of pretty radically changing compilation by reducing the number of codegen units to 1 in all cases.

Thank you for bring this up. Yes, at the moment, -Z no-link would only allow 1 codegen units. I am working on enhancing it to support multiple CGUs. It'll basically make --emit obj to support multiple CGUs.

@Centril
Copy link
Contributor

Centril commented Dec 15, 2019

config.rs, do we still want to refactor this file? @Centril @tmandry

@0dvictor Yes, definitely, and I think that:

I don't personally love the idea of separating the primary data structure definition of Options from the code that builds it.

...is not something I agree with. :) In particular, it makes a whole lot of sense to separate data definitions and logic so that things are more pluggable and it's also better in general for incremental. This is precisely the thing we've been trying to do with splitting libsyntax from the parser. So I want to encourage your refactoring proposal.

@alexcrichton
Copy link
Member

@0dvictor

It'll basically make --emit obj to support multiple CGUs.

As a heads up that's unfortunately a breaking change since --emit obj only emits one object file today, so there likely needs to be a different route to implement this. I think that we'll benefit from a more "first class" implementation as well rather than trying to patch together a few other options to make this work.

@bjorn3
Copy link
Member

bjorn3 commented Dec 16, 2019

Maybe have something like --emit delayed-link (not --emit obj) to emit all object files necessary for linking combined with a .rlink file and then something like rustc crate.rlink to perform the linking.

@0dvictor
Copy link
Contributor Author

As a heads up that's unfortunately a breaking change since --emit obj only emits one object file today, so there likely needs to be a different route to implement this.

Good point. Let me think about it and update the changes.

BTW, unrelated to -Z no-link but out of curiosity: if --emit obj should always generate one file, why do we have to disable parallel compilation? Technically we could still compile in parallel with multiple CGUs, but at the end, we can combine all CGUs with llvm::Linker so that we still get one obj file.

@0dvictor
Copy link
Contributor Author

Maybe have something like --emit delayed-link (not --emit obj) to emit all object files necessary for linking combined with a .rlink file and then something like rustc crate.rlink to perform the linking.

Good suggestion, and it should work well with your previous suggestion on serializing CrateInfo. Working on it.

@alexcrichton
Copy link
Member

@0dvictor that's possible yeah! It's not as parallel since codegen is still serial (one big object file), but it's probably best to leave all this to a separate issue.

@bors
Copy link
Contributor

bors commented Dec 20, 2019

☔ The latest upstream changes (presumably #67449) made this pull request unmergeable. Please resolve the merge conflicts.

impl rustc_serialize::UseSpecializedDecodable for CrateNum {}
impl rustc_serialize::UseSpecializedEncodable for CrateNum {
fn default_encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
e.emit_u32(self.as_u32())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct, as the crate numbers may be mapped differently in a different compilation session. Only the Svh is guaranteed to remain the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for bringing this up. I was actually struggled a lot trying to emit the correct data. I believe we can safely simply emit the crate number here.
As you pointed out, the crate numbers is only meaningful within the same compilation session; therefore, one must have the session info when using crate numbers. For example, one might need include a crate number -> Svh mapping table in the serialized data, or some other ways to correctly map crate numbers to the actual crates.

In this PR, crate numbers are used within one CodegenResults, and CodegenResults only belongs to one specific session; therefore, crate numbers are unique. Then we can use CodegenResults.crate_info.used_crate_source to find the crate from a crate number.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also replaced the Encodable impl of CrateNum for other usages. Maybe make a new LinkingCrateNum newtype for u32 and store that in crate_info instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this Encodable impl is currently used since the default impl just returns an error.
However, I like your idea of making a new LinkingCrateNum as it conceptually decouples CrateInfo from a compilation session. I'll update accordingly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created #67516 for decoupling CrateNum from the compilation session. @bjorn3 could you take a look?

fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
let krate = u64::from(self.krate.as_u32());
let index = u64::from(self.index.as_u32());
s.emit_u64((krate<<32) | index)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, a DefId is conceptually an interned DefPath.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to CrateNum, one should include a DefId to DefPath mapping in the serialized data. However, in this PR, DefId isn't used by the linker so that the mapping can be safely omitted.

@0dvictor
Copy link
Contributor Author

Ping from triage: @0dvictor can you please address the merge conflicts? Thanks.

Thank you for reminding. I have rebased and resolved the conflicts; initially, I was plan to wait for the review of #67516, as it is to resolve concerns of this PR.

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-7 of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2020-01-19T12:10:44.8229490Z ========================== Starting Command Output ===========================
2020-01-19T12:10:44.8269317Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/d96239a8-6e89-49d2-9276-aae83c16a230.sh
2020-01-19T12:10:44.8269535Z 
2020-01-19T12:10:44.8273180Z ##[section]Finishing: Disable git automatic line ending conversion
2020-01-19T12:10:44.8279510Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/67195/merge to s
2020-01-19T12:10:44.8281661Z Task         : Get sources
2020-01-19T12:10:44.8281694Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-01-19T12:10:44.8281773Z Version      : 1.0.0
2020-01-19T12:10:44.8281806Z Author       : Microsoft
---
2020-01-19T12:10:45.8802517Z ##[command]git remote add origin https://github.com/rust-lang/rust
2020-01-19T12:10:45.8822915Z ##[command]git config gc.auto 0
2020-01-19T12:10:45.8827461Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2020-01-19T12:10:45.8829833Z ##[command]git config --get-all http.proxy
2020-01-19T12:10:45.8841907Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/67195/merge:refs/remotes/pull/67195/merge

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@0dvictor
Copy link
Contributor Author

Rebase again to fix the tidy error.

Copy link
Member

@tmandry tmandry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at the moment, -Z no-link would only allow 1 codegen units. I am working on enhancing it to support multiple CGUs.

@0dvictor what's the status of this? It doesn't look like you're changing the output types anymore. Does that mean multiple CGUs are supported now?

There was some discussion about --emit delayed-link but I'm not sure if it's needed. To my eyes everything looks good.

@@ -160,6 +160,7 @@ pub enum ExternCrateSource {
Path,
}

#[derive(RustcEncodable, RustcDecodable)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to save this in a binary file rather than escaped binary in a json string.

That said, I'm okay with doing this later, especially since this is an experimental feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agreed, a binary file is definitely the proper way. I chose JSON in this PR purely because I don't want the file format details hold the feature, especially the proposed approach has not been reviewed yet.

@@ -86,8 +87,16 @@ impl fmt::Display for CrateNum {
}
}

impl rustc_serialize::UseSpecializedEncodable for CrateNum {}
impl rustc_serialize::UseSpecializedDecodable for CrateNum {}
impl rustc_serialize::UseSpecializedEncodable for CrateNum {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we decided to stick with this approach (#67516 (comment)), we may want to add a comment (here or on CrateNum) saying which conditions have to hold when using this.

@0dvictor
Copy link
Contributor Author

what's the status of this? It doesn't look like you're changing the output types anymore. Does that mean multiple CGUs are supported now?

Correct, multiple CGUs are naturally supported; no extra work is needed.

There was some discussion about --emit delayed-link but I'm not sure if it's needed. To my eyes everything looks good.

Yes, though I like the idea of --emit delayed-link, I don't think it is proper at current stage. As an experimental/unstable feature, a -Z option serves better. I would like to discuss about it more when we decide to stabilize the feature.

@bjorn3
Copy link
Member

bjorn3 commented Jan 22, 2020

It is possible to hide non -Z options behind -Zunstable-options.

@tmandry
Copy link
Member

tmandry commented Jan 22, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Jan 22, 2020

📌 Commit be86fb3 has been approved by tmandry

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 22, 2020
tmandry added a commit to tmandry/rust that referenced this pull request Jan 22, 2020
[experiment] Add `-Z no-link` flag

Adds a compiler option to allow rustc compile a crate without linking.
With this flag, `rustc` serializes codegen_results into a `.rlink` file.

Part of Issue rust-lang#64191
@bors
Copy link
Contributor

bors commented Jan 22, 2020

⌛ Testing commit be86fb3 with merge 089b0632c6ece90649d7b94596970f458cb9d292...

Adds a compiler option to allow rustc compile a crate without linking.
With this flag, rustc serializes codegen_results into a .rlink file.
@tmandry
Copy link
Member

tmandry commented Jan 23, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Jan 23, 2020

📌 Commit 6a6ebb4 has been approved by tmandry

tmandry added a commit to tmandry/rust that referenced this pull request Jan 23, 2020
[experiment] Add `-Z no-link` flag

Adds a compiler option to allow rustc compile a crate without linking.
With this flag, `rustc` serializes codegen_results into a `.rlink` file.

Part of Issue rust-lang#64191
@bors
Copy link
Contributor

bors commented Jan 23, 2020

⌛ Testing commit 6a6ebb4 with merge 26fe0c8fa84a65deb9fe8ee6f2b928ed817c1d0b...

@0dvictor
Copy link
Contributor Author

Thank you all for reviewing and guiding me through the process. I just accepted the suggested changes, squashed all commits into one, and rebased to the latest. The PR is good to go.

@tmandry
Copy link
Member

tmandry commented Jan 23, 2020

@bors retry rolled up

bors added a commit that referenced this pull request Jan 23, 2020
Rollup of 10 pull requests

Successful merges:

 - #67195 ([experiment] Add `-Z no-link` flag)
 - #68253 (add bare metal ARM Cortex-A targets to rustc)
 - #68361 (Unbreak linking with lld 9 on FreeBSD 13.0-CURRENT i386)
 - #68388 (Make `TooGeneric` error in WF checking a proper error)
 - #68409 (Micro-optimize OutputFilenames)
 - #68410 (Export weak symbols used by MemorySanitizer)
 - #68425 (Fix try-op diagnostic in E0277 for methods)
 - #68440 (bootstrap: update clippy subcmd decription)
 - #68441 (pprust: use as_deref)
 - #68462 (librustc_mir: don't allocate vectors where slices will do.)

Failed merges:

r? @ghost
@rust-highfive
Copy link
Collaborator

Your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@bors
Copy link
Contributor

bors commented Jan 23, 2020

⌛ Testing commit 6a6ebb4 with merge e23dd66...

@bors bors merged commit 6a6ebb4 into rust-lang:master Jan 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants