]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Add `-C lto=val` option
authorAlex Crichton <alex@alexcrichton.com>
Tue, 16 Jan 2018 23:02:31 +0000 (15:02 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 23 Jan 2018 22:13:47 +0000 (14:13 -0800)
This commit primarily adds the ability to control what kind of LTO happens when
rustc performs LTO, namely allowing values to be specified to the `-C lto`
option, such as `-C lto=thin` and `-C lto=fat`. (where "fat" is the previous
kind of LTO, throw everything in one giant module)

Along the way this also refactors a number of fields which store information
about whether LTO/ThinLTO are enabled to unify them all into one field through
which everything is dispatched, hopefully removing a number of special cases
throughout.

This is intended to help mitigate #47409 but will require a backport as well,
and this would unfortunately need to be an otherwise insta-stable option.

src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/lto.rs
src/librustc_trans/back/write.rs
src/test/run-make/codegen-options-parsing/Makefile
src/test/run-pass/fat-lto.rs [new file with mode: 0644]
src/test/run-pass/thinlto/all-crates.rs [new file with mode: 0644]
src/test/run-pass/thinlto/thin-lto-inlines2.rs

index da119ba45694dea17fedfd05623be94ee43b95b6..3fac9ce41f1397e1fed9a6b41c1108665e2f7b4b 100644 (file)
@@ -72,6 +72,26 @@ pub enum OptLevel {
     SizeMin, // -Oz
 }
 
+#[derive(Clone, Copy, PartialEq, Hash)]
+pub enum Lto {
+    /// Don't do any LTO whatsoever
+    No,
+
+    /// Do a full crate graph LTO. The flavor is determined by the compiler
+    /// (currently the default is "fat").
+    Yes,
+
+    /// Do a full crate graph LTO with ThinLTO
+    Thin,
+
+    /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
+    /// units).
+    ThinLocal,
+
+    /// Do a full crate graph LTO with "fat" LTO
+    Fat,
+}
+
 #[derive(Clone, Copy, PartialEq, Hash)]
 pub enum DebugInfoLevel {
     NoDebugInfo,
@@ -389,7 +409,7 @@ pub struct Options {
         // 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: Option<bool> [UNTRACKED],
+        cli_forced_thinlto_off: bool [UNTRACKED],
     }
 );
 
@@ -590,7 +610,7 @@ pub fn basic_options() -> Options {
         debug_assertions: true,
         actually_rustdoc: false,
         cli_forced_codegen_units: None,
-        cli_forced_thinlto: None,
+        cli_forced_thinlto_off: false,
     }
 }
 
@@ -780,11 +800,13 @@ mod $mod_desc {
             Some("crate=integer");
         pub const parse_unpretty: Option<&'static str> =
             Some("`string` or `string=string`");
+        pub const parse_lto: Option<&'static str> =
+            Some("one of `thin`, `fat`, or omitted");
     }
 
     #[allow(dead_code)]
     mod $mod_set {
-        use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer};
+        use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
         use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel};
         use std::path::PathBuf;
 
@@ -978,6 +1000,16 @@ fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
                 _ => false,
             }
         }
+
+        fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
+            *slot = match v {
+                None => Lto::Yes,
+                Some("thin") => Lto::Thin,
+                Some("fat") => Lto::Fat,
+                Some(_) => return false,
+            };
+            true
+        }
     }
 ) }
 
@@ -994,7 +1026,7 @@ fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
         "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: bool = (false, parse_bool, [TRACKED],
+    lto: Lto = (Lto::No, 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)"),
@@ -1677,7 +1709,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
 
     let mut cg = build_codegen_options(matches, error_format);
     let mut codegen_units = cg.codegen_units;
-    let mut thinlto = None;
+    let mut disable_thinlto = false;
 
     // Issue #30063: if user requests llvm-related output to one
     // particular path, disable codegen-units.
@@ -1699,12 +1731,12 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
                     }
                     early_warn(error_format, "resetting to default -C codegen-units=1");
                     codegen_units = Some(1);
-                    thinlto = Some(false);
+                    disable_thinlto = true;
                 }
             }
             _ => {
                 codegen_units = Some(1);
-                thinlto = Some(false);
+                disable_thinlto = true;
             }
         }
     }
@@ -1734,7 +1766,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         (&None, &None) => None,
     }.map(|m| PathBuf::from(m));
 
-    if cg.lto && incremental.is_some() {
+    if cg.lto != Lto::No && incremental.is_some() {
         early_error(error_format, "can't perform LTO when compiling incrementally");
     }
 
@@ -1934,7 +1966,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         debug_assertions,
         actually_rustdoc: false,
         cli_forced_codegen_units: codegen_units,
-        cli_forced_thinltothinlto,
+        cli_forced_thinlto_off: disable_thinlto,
     },
     cfg)
 }
@@ -2052,7 +2084,7 @@ mod dep_tracking {
     use std::hash::Hash;
     use std::path::PathBuf;
     use std::collections::hash_map::DefaultHasher;
-    use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
+    use super::{Passes, CrateType, OptLevel, DebugInfoLevel, Lto,
                 OutputTypes, Externs, ErrorOutputType, Sanitizer};
     use syntax::feature_gate::UnstableFeatures;
     use rustc_back::{PanicStrategy, RelroLevel};
@@ -2107,6 +2139,7 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_via_hash!(RelroLevel);
     impl_dep_tracking_hash_via_hash!(Passes);
     impl_dep_tracking_hash_via_hash!(OptLevel);
+    impl_dep_tracking_hash_via_hash!(Lto);
     impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
     impl_dep_tracking_hash_via_hash!(Externs);
@@ -2180,6 +2213,7 @@ mod tests {
     use lint;
     use middle::cstore;
     use session::config::{build_configuration, build_session_options_and_crate_config};
+    use session::config::Lto;
     use session::build_session;
     use std::collections::{BTreeMap, BTreeSet};
     use std::iter::FromIterator;
@@ -2656,7 +2690,7 @@ fn test_codegen_options_tracking_hash() {
 
         // Make sure changing a [TRACKED] option changes the hash
         opts = reference.clone();
-        opts.cg.lto = true;
+        opts.cg.lto = Lto::Fat;
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
         opts = reference.clone();
index 36f716a4a76942c8e85364c640f18bb68ff95440..02cd6a92eb7618b43847978e80eb6cc40c76ce51 100644 (file)
@@ -498,9 +498,65 @@ pub fn emit_end_regions(&self) -> bool {
             self.use_mir()
     }
 
-    pub fn lto(&self) -> bool {
-        self.opts.cg.lto || self.target.target.options.requires_lto
+    /// Calculates the flavor of LTO to use for this compilation.
+    pub fn lto(&self) -> config::Lto {
+        // If our target has codegen requirements ignore the command line
+        if self.target.target.options.requires_lto {
+            return config::Lto::Fat
+        }
+
+        // If the user specified something, return that. If they only said `-C
+        // lto` and we've for whatever reason forced off ThinLTO via the CLI,
+        // then ensure we can't use a ThinLTO.
+        match self.opts.cg.lto {
+            config::Lto::No => {}
+            config::Lto::Yes if self.opts.cli_forced_thinlto_off => {
+                return config::Lto::Fat
+            }
+            other => return other,
+        }
+
+        // Ok at this point the target doesn't require anything and the user
+        // hasn't asked for anything. Our next decision is whether or not
+        // we enable "auto" ThinLTO where we use multiple codegen units and
+        // then do ThinLTO over those codegen units. The logic below will
+        // either return `No` or `ThinLocal`.
+
+        // If processing command line options determined that we're incompatible
+        // with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option.
+        if self.opts.cli_forced_thinlto_off {
+            return config::Lto::No
+        }
+
+        // If `-Z thinlto` specified process that, but note that this is mostly
+        // a deprecated option now that `-C lto=thin` exists.
+        if let Some(enabled) = self.opts.debugging_opts.thinlto {
+            if enabled {
+                return config::Lto::ThinLocal
+            } else {
+                return config::Lto::No
+            }
+        }
+
+        // If there's only one codegen unit and LTO isn't enabled then there's
+        // no need for ThinLTO so just return false.
+        if self.codegen_units() == 1 {
+            return config::Lto::No
+        }
+
+        // Right now ThinLTO isn't compatible with incremental compilation.
+        if self.opts.incremental.is_some() {
+            return config::Lto::No
+        }
+
+        // Now we're in "defaults" territory. By default we enable ThinLTO for
+        // optimized compiles (anything greater than O0).
+        match self.opts.optimize {
+            config::OptLevel::No => config::Lto::No,
+            _ => config::Lto::ThinLocal,
+        }
     }
+
     /// Returns the panic strategy for this compile session. If the user explicitly selected one
     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
     pub fn panic_strategy(&self) -> PanicStrategy {
@@ -804,38 +860,6 @@ pub fn codegen_units(&self) -> usize {
         // scientific.
         16
     }
-
-    /// Returns whether ThinLTO is enabled for this compilation
-    pub fn thinlto(&self) -> bool {
-        // If processing command line options determined that we're incompatible
-        // with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option.
-        if let Some(enabled) = self.opts.cli_forced_thinlto {
-            return enabled
-        }
-
-        // If explicitly specified, use that with the next highest priority
-        if let Some(enabled) = self.opts.debugging_opts.thinlto {
-            return enabled
-        }
-
-        // If there's only one codegen unit and LTO isn't enabled then there's
-        // no need for ThinLTO so just return false.
-        if self.codegen_units() == 1 && !self.lto() {
-            return false
-        }
-
-        // Right now ThinLTO isn't compatible with incremental compilation.
-        if self.opts.incremental.is_some() {
-            return false
-        }
-
-        // Now we're in "defaults" territory. By default we enable ThinLTO for
-        // optimized compiles (anything greater than O0).
-        match self.opts.optimize {
-            config::OptLevel::No => false,
-            _ => true,
-        }
-    }
 }
 
 pub fn build_session(sopts: config::Options,
index 923e5549927de95fe6a2832ed1f17b4ce96661a3..f050edcd513b918167fd49355050327a64716b8e 100644 (file)
@@ -16,7 +16,7 @@
 use super::rpath;
 use metadata::METADATA_FILENAME;
 use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest};
-use rustc::session::config::RUST_CGU_EXT;
+use rustc::session::config::{RUST_CGU_EXT, Lto};
 use rustc::session::filesearch;
 use rustc::session::search_paths::PathKind;
 use rustc::session::Session;
@@ -503,7 +503,8 @@ fn link_staticlib(sess: &Session,
         });
         ab.add_rlib(path,
                     &name.as_str(),
-                    sess.lto() && !ignored_for_lto(sess, &trans.crate_info, cnum),
+                    is_full_lto_enabled(sess) &&
+                        !ignored_for_lto(sess, &trans.crate_info, cnum),
                     skip_object_files).unwrap();
 
         all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned());
@@ -1211,7 +1212,8 @@ fn add_static_crate(cmd: &mut Linker,
             lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
         });
 
-        if (!sess.lto() || ignored_for_lto(sess, &trans.crate_info, cnum)) &&
+        if (!is_full_lto_enabled(sess) ||
+            ignored_for_lto(sess, &trans.crate_info, cnum)) &&
            crate_type != config::CrateTypeDylib &&
            !skip_native {
             cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
@@ -1264,7 +1266,7 @@ fn looks_like_rust(s: &str) -> bool {
                 // file, then we don't need the object file as it's part of the
                 // LTO module. Note that `#![no_builtins]` is excluded from LTO,
                 // though, so we let that object file slide.
-                let skip_because_lto = sess.lto() &&
+                let skip_because_lto = is_full_lto_enabled(sess) &&
                     is_rust_object &&
                     (sess.target.target.options.no_builtins ||
                      !trans.crate_info.is_no_builtins.contains(&cnum));
@@ -1301,7 +1303,7 @@ fn looks_like_rust(s: &str) -> bool {
     fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) {
         // If we're performing LTO, then it should have been previously required
         // that all upstream rust dependencies were available in an rlib format.
-        assert!(!sess.lto());
+        assert!(!is_full_lto_enabled(sess));
 
         // Just need to tell the linker about where the library lives and
         // what its name is
@@ -1409,3 +1411,13 @@ fn link_binaryen(sess: &Session,
                             e));
     }
 }
+
+fn is_full_lto_enabled(sess: &Session) -> bool {
+    match sess.lto() {
+        Lto::Yes |
+        Lto::Thin |
+        Lto::Fat => true,
+        Lto::No |
+        Lto::ThinLocal => false,
+    }
+}
index b612247ffcd42bfbd867cd4677e5ee9000ece992..9ff5bcf7a33caaa5772aaf8e822ef673e6e6f281 100644 (file)
@@ -18,7 +18,7 @@
 use llvm;
 use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::middle::exported_symbols::SymbolExportLevel;
-use rustc::session::config;
+use rustc::session::config::{self, Lto};
 use rustc::util::common::time;
 use time_graph::Timeline;
 use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource};
@@ -95,25 +95,22 @@ pub fn cost(&self) -> u64 {
     }
 }
 
-pub enum LTOMode {
-    WholeCrateGraph,
-    JustThisCrate,
-}
-
 pub(crate) fn run(cgcx: &CodegenContext,
-           modules: Vec<ModuleTranslation>,
-           mode: LTOMode,
-           timeline: &mut Timeline)
+                  modules: Vec<ModuleTranslation>,
+                  timeline: &mut Timeline)
     -> Result<Vec<LtoModuleTranslation>, FatalError>
 {
     let diag_handler = cgcx.create_diag_handler();
-    let export_threshold = match mode {
-        LTOMode::WholeCrateGraph => {
+    let export_threshold = match cgcx.lto {
+        // We're just doing LTO for our one crate
+        Lto::ThinLocal => SymbolExportLevel::Rust,
+
+        // We're doing LTO for the entire crate graph
+        Lto::Yes | Lto::Fat | Lto::Thin => {
             symbol_export::crates_export_threshold(&cgcx.crate_types)
         }
-        LTOMode::JustThisCrate => {
-            SymbolExportLevel::Rust
-        }
+
+        Lto::No => panic!("didn't request LTO but we're doing LTO"),
     };
 
     let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
@@ -140,7 +137,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
     // We save off all the bytecode and LLVM module ids for later processing
     // with either fat or thin LTO
     let mut upstream_modules = Vec::new();
-    if let LTOMode::WholeCrateGraph = mode {
+    if cgcx.lto != Lto::ThinLocal {
         if cgcx.opts.cg.prefer_dynamic {
             diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
                         .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
@@ -186,13 +183,16 @@ pub(crate) fn run(cgcx: &CodegenContext,
     }
 
     let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
-    match mode {
-        LTOMode::WholeCrateGraph if !cgcx.thinlto => {
+    match cgcx.lto {
+        Lto::Yes | // `-C lto` == fat LTO by default
+        Lto::Fat => {
             fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
         }
-        _ => {
+        Lto::Thin |
+        Lto::ThinLocal => {
             thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
         }
+        Lto::No => unreachable!(),
     }
 }
 
index a013af7a4600ef342218823abbbea1d890e26de1..a4af080ebf7e6f7e6d0effc2687e51aa5c9aef4c 100644 (file)
@@ -19,7 +19,7 @@
 use rustc::dep_graph::{DepGraph, WorkProductFileKind};
 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
-                             AllPasses, Sanitizer};
+                             AllPasses, Sanitizer, Lto};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
 use rustc_back::LinkerFlavor;
@@ -318,8 +318,7 @@ fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
 pub struct CodegenContext {
     // Resouces needed when running LTO
     pub time_passes: bool,
-    pub lto: bool,
-    pub thinlto: bool,
+    pub lto: Lto,
     pub no_landing_pads: bool,
     pub save_temps: bool,
     pub fewer_names: bool,
@@ -576,12 +575,7 @@ fn generate_lto_work(cgcx: &CodegenContext,
                  TRANS_WORK_PACKAGE_KIND,
                  "generate lto")
     }).unwrap_or(Timeline::noop());
-    let mode = if cgcx.lto {
-        lto::LTOMode::WholeCrateGraph
-    } else {
-        lto::LTOMode::JustThisCrate
-    };
-    let lto_modules = lto::run(cgcx, modules, mode, &mut timeline)
+    let lto_modules = lto::run(cgcx, modules, &mut timeline)
         .unwrap_or_else(|e| panic!(e));
 
     lto_modules.into_iter().map(|module| {
@@ -1280,28 +1274,51 @@ fn execute_work_item(cgcx: &CodegenContext,
         unsafe {
             optimize(cgcx, &diag_handler, &mtrans, config, timeline)?;
 
-            let lto = cgcx.lto;
+            // After we've done the initial round of optimizations we need to
+            // decide whether to synchronously codegen this module or ship it
+            // back to the coordinator thread for further LTO processing (which
+            // has to wait for all the initial modules to be optimized).
+            //
+            // Here we dispatch based on the `cgcx.lto` and kind of module we're
+            // translating...
+            let needs_lto = match cgcx.lto {
+                Lto::No => false,
+
+                // Here we've got a full crate graph LTO requested. We ignore
+                // this, however, if the crate type is only an rlib as there's
+                // no full crate graph to process, that'll happen later.
+                //
+                // This use case currently comes up primarily for targets that
+                // require LTO so the request for LTO is always unconditionally
+                // passed down to the backend, but we don't actually want to do
+                // anything about it yet until we've got a final product.
+                Lto::Yes | Lto::Fat | Lto::Thin => {
+                    cgcx.crate_types.len() != 1 ||
+                        cgcx.crate_types[0] != config::CrateTypeRlib
+                }
 
-            let auto_thin_lto =
-                cgcx.thinlto &&
-                cgcx.total_cgus > 1 &&
-                mtrans.kind != ModuleKind::Allocator;
+                // When we're automatically doing ThinLTO for multi-codegen-unit
+                // builds we don't actually want to LTO the allocator modules if
+                // it shows up. This is due to various linker shenanigans that
+                // we'll encounter later.
+                //
+                // Additionally here's where we also factor in the current LLVM
+                // version. If it doesn't support ThinLTO we skip this.
+                Lto::ThinLocal => {
+                    mtrans.kind != ModuleKind::Allocator &&
+                        llvm::LLVMRustThinLTOAvailable()
+                }
+            };
 
-            // If we're a metadata module we never participate in LTO.
-            //
-            // If LTO was explicitly requested on the command line, we always
-            // LTO everything else.
-            //
-            // If LTO *wasn't* explicitly requested and we're not a metdata
-            // module, then we may automatically do ThinLTO if we've got
-            // multiple codegen units. Note, however, that the allocator module
-            // doesn't participate here automatically because of linker
-            // shenanigans later on.
-            if mtrans.kind == ModuleKind::Metadata || (!lto && !auto_thin_lto) {
+            // Metadata modules never participate in LTO regardless of the lto
+            // settings.
+            let needs_lto = needs_lto && mtrans.kind != ModuleKind::Metadata;
+
+            if needs_lto {
+                Ok(WorkItemResult::NeedsLTO(mtrans))
+            } else {
                 let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?;
                 Ok(WorkItemResult::Compiled(module))
-            } else {
-                Ok(WorkItemResult::NeedsLTO(mtrans))
             }
         }
     }
@@ -1377,28 +1394,13 @@ fn start_executing_work(tcx: TyCtxt,
         each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
     }));
 
-    let crate_types = sess.crate_types.borrow();
-    let only_rlib = crate_types.len() == 1 &&
-        crate_types[0] == config::CrateTypeRlib;
-
     let wasm_import_memory =
         attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory");
 
     let cgcx = CodegenContext {
         crate_types: sess.crate_types.borrow().clone(),
         each_linked_rlib_for_lto,
-        // If we're only building an rlibc then allow the LTO flag to be passed
-        // but don't actually do anything, the full LTO will happen later
-        lto: sess.lto() && !only_rlib,
-
-        // Enable ThinLTO if requested, but only if the target we're compiling
-        // for doesn't require full LTO. Some targets require one LLVM module
-        // (they effectively don't have a linker) so it's up to us to use LTO to
-        // link everything together.
-        thinlto: sess.thinlto() &&
-            !sess.target.target.options.requires_lto &&
-            unsafe { llvm::LLVMRustThinLTOAvailable() },
-
+        lto: sess.lto(),
         no_landing_pads: sess.no_landing_pads(),
         fewer_names: sess.fewer_names(),
         save_temps: sess.opts.cg.save_temps,
index 81e06043c87aebef346de8313f2f3e0a5c3e97f7..fda96a8b1fb5eb0bad399e2cbe0d971161c01ece 100644 (file)
@@ -16,11 +16,11 @@ all:
        $(RUSTC) -C extra-filename=foo dummy.rs 2>&1
        #Option taking no argument
        $(RUSTC) -C lto= dummy.rs 2>&1 | \
-               $(CGREP) 'codegen option `lto` takes no value'
+               $(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
        $(RUSTC) -C lto=1 dummy.rs 2>&1 | \
-               $(CGREP) 'codegen option `lto` takes no value'
+               $(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
        $(RUSTC) -C lto=foo dummy.rs 2>&1 | \
-               $(CGREP) 'codegen option `lto` takes no value'
+               $(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
        $(RUSTC) -C lto dummy.rs
 
        # Should not link dead code...
diff --git a/src/test/run-pass/fat-lto.rs b/src/test/run-pass/fat-lto.rs
new file mode 100644 (file)
index 0000000..453eede
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Clto=fat
+// no-prefer-dynamic
+
+fn main() {
+    println!("hello!");
+}
+
diff --git a/src/test/run-pass/thinlto/all-crates.rs b/src/test/run-pass/thinlto/all-crates.rs
new file mode 100644 (file)
index 0000000..772a9ec
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Clto=thin
+// no-prefer-dynamic
+// min-llvm-version 4.0
+
+fn main() {
+    println!("hello!");
+}
index 0e8ad08a5f6804c26caed1237fba12c5b32d3c80..6020f72415dad2740d2d543a8ec2c4fef1a7d29e 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
+// compile-flags: -C codegen-units=8 -O -C lto=thin
 // aux-build:thin-lto-inlines-aux.rs
 // min-llvm-version 4.0
 // no-prefer-dynamic