]> git.lizzy.rs Git - rust.git/commitdiff
Merge branch 'no-stderr-sink' of https://github.com/Zoxc/rust into rollup
authorAlex Crichton <alex@alexcrichton.com>
Fri, 26 Jan 2018 14:49:55 +0000 (06:49 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 26 Jan 2018 14:49:55 +0000 (06:49 -0800)
1  2 
src/librustc/hir/lowering.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc_trans/back/write.rs

index dc2f2583c0177c1ddc687b2b2175f739894e620e,bc7a1137d84a9816957af75823049acef3d1042d..f2f420c91dd1a1455375f7f9f5afbca70784de2c
@@@ -773,22 -773,22 +773,22 @@@ impl<'a> LoweringContext<'a> 
          *self.name_map.entry(ident).or_insert_with(|| Symbol::from_ident(ident))
      }
  
 -    fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned<Name>> {
 -        o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
 +    fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
 +        label.map(|label| hir::Label { name: label.ident.name, span: label.span })
      }
  
 -    fn lower_loop_destination(&mut self, destination: Option<(NodeId, Spanned<Ident>)>)
 +    fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>)
          -> hir::Destination
      {
          match destination {
 -            Some((id, label_ident)) => {
 +            Some((id, label)) => {
                  let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
                      hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id)
                  } else {
                      hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
                  };
                  hir::Destination {
 -                    ident: Some(label_ident),
 +                    label: self.lower_label(Some(label)),
                      target_id: hir::ScopeTarget::Loop(target),
                  }
              },
                                    .map(|innermost_loop_id| *innermost_loop_id);
  
                  hir::Destination {
 -                    ident: None,
 +                    label: None,
                      target_id: hir::ScopeTarget::Loop(
                          loop_id.map(|id| Ok(self.lower_node_id(id).node_id))
                                 .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
  
                  hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt)
              }
 -            ExprKind::While(ref cond, ref body, opt_ident) => {
 +            ExprKind::While(ref cond, ref body, opt_label) => {
                  self.with_loop_scope(e.id, |this|
                      hir::ExprWhile(
                          this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
                          this.lower_block(body, false),
 -                        this.lower_opt_sp_ident(opt_ident)))
 +                        this.lower_label(opt_label)))
              }
 -            ExprKind::Loop(ref body, opt_ident) => {
 +            ExprKind::Loop(ref body, opt_label) => {
                  self.with_loop_scope(e.id, |this|
                      hir::ExprLoop(this.lower_block(body, false),
 -                                  this.lower_opt_sp_ident(opt_ident),
 +                                  this.lower_label(opt_label),
                                    hir::LoopSource::Loop))
              }
              ExprKind::Catch(ref body) => {
                      (&None, &Some(..), Closed) => "RangeToInclusive",
                      (&Some(..), &Some(..), Closed) => "RangeInclusive",
                      (_, &None, Closed) =>
-                         panic!(self.diagnostic().span_fatal(
-                             e.span, "inclusive range with no end")),
+                         self.diagnostic().span_fatal(
+                             e.span, "inclusive range with no end").raise(),
                  };
  
                  let fields =
                  hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional,
                                                 ImplTraitContext::Disallowed))
              }
 -            ExprKind::Break(opt_ident, ref opt_expr) => {
 -                let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
 +            ExprKind::Break(opt_label, ref opt_expr) => {
 +                let destination = if self.is_in_loop_condition && opt_label.is_none() {
                      hir::Destination {
 -                        ident: opt_ident,
 +                        label: None,
                          target_id: hir::ScopeTarget::Loop(
                                  Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
                      }
                  } else {
 -                    self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident)))
 +                    self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
                  };
                  hir::ExprBreak(
 -                        label_result,
 +                        destination,
                          opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
              }
 -            ExprKind::Continue(opt_ident) =>
 +            ExprKind::Continue(opt_label) =>
                  hir::ExprAgain(
 -                    if self.is_in_loop_condition && opt_ident.is_none() {
 +                    if self.is_in_loop_condition && opt_label.is_none() {
                          hir::Destination {
 -                            ident: opt_ident,
 +                            label: None,
                              target_id: hir::ScopeTarget::Loop(Err(
                                  hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
                          }
                      } else {
 -                        self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident)))
 +                        self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
                      }),
              ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
              ExprKind::InlineAsm(ref asm) => {
  
              // Desugar ExprWhileLet
              // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
 -            ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
 +            ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
                  // to:
                  //
                  //   [opt_ident]: loop {
  
                  // `[opt_ident]: loop { ... }`
                  let loop_block = P(self.block_expr(P(match_expr)));
 -                let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
 +                let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
                                                hir::LoopSource::WhileLet);
                  // add attributes to the outer returned expr node
                  loop_expr
  
              // Desugar ExprForLoop
              // From: `[opt_ident]: for <pat> in <head> <body>`
 -            ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => {
 +            ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
                  // to:
                  //
                  //   {
                                                    None));
  
                  // `[opt_ident]: loop { ... }`
 -                let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
 +                let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
                                                hir::LoopSource::ForLoop);
                  let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
                  let loop_expr = P(hir::Expr {
                              e.span,
                              hir::ExprBreak(
                                  hir::Destination {
 -                                    ident: None,
 +                                    label: None,
                                      target_id: hir::ScopeTarget::Block(catch_node),
                                  },
                                  Some(from_err_expr)
index 3fac9ce41f1397e1fed9a6b41c1108665e2f7b4b,466bfa3e4e4cfbcb8b2afe2982b521902b2d5deb..a4f347d4687877031d2311400a08e0482278a7cc
@@@ -72,26 -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,
@@@ -409,7 -389,7 +409,7 @@@ top_level_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],
      }
  );
  
@@@ -610,7 -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,
      }
  }
  
@@@ -800,13 -780,11 +800,13 @@@ macro_rules! options 
              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;
  
                  _ => 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
 +        }
      }
  ) }
  
@@@ -1026,7 -994,7 +1026,7 @@@ options! {CodegenOptions, CodegenSetter
          "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)"),
@@@ -1365,7 -1333,7 +1365,7 @@@ pub fn build_target_config(opts: &Optio
              sp.struct_fatal(&format!("Error loading target specification: {}", e))
                  .help("Use `--print target-list` for a list of built-in targets")
                  .emit();
-             panic!(FatalError);
+             FatalError.raise();
          }
      };
  
          "16" => (ast::IntTy::I16, ast::UintTy::U16),
          "32" => (ast::IntTy::I32, ast::UintTy::U32),
          "64" => (ast::IntTy::I64, ast::UintTy::U64),
-         w    => panic!(sp.fatal(&format!("target specification was invalid: \
-                                           unrecognized target-pointer-width {}", w))),
+         w    => sp.fatal(&format!("target specification was invalid: \
+                                           unrecognized target-pointer-width {}", w)).raise(),
      };
  
      Config {
@@@ -1709,7 -1677,7 +1709,7 @@@ pub fn build_session_options_and_crate_
  
      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.
                      }
                      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;
              }
          }
      }
          (&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");
      }
  
          debug_assertions,
          actually_rustdoc: false,
          cli_forced_codegen_units: codegen_units,
 -        cli_forced_thinltothinlto,
 +        cli_forced_thinlto_off: disable_thinlto,
      },
      cfg)
  }
@@@ -2084,7 -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};
      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);
@@@ -2213,7 -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;
  
          // 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 02cd6a92eb7618b43847978e80eb6cc40c76ce51,be796129ed49e62880c6ceca2e384d849a5254e1..568ae77c964c8f3782173d36e94cd766bd22bd85
@@@ -250,7 -250,7 +250,7 @@@ impl Session 
      }
  
      pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
-         panic!(self.diagnostic().span_fatal(sp, msg))
+         self.diagnostic().span_fatal(sp, msg).raise()
      }
      pub fn span_fatal_with_code<S: Into<MultiSpan>>(
          &self,
          msg: &str,
          code: DiagnosticId,
      ) -> ! {
-         panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
+         self.diagnostic().span_fatal_with_code(sp, msg, code).raise()
      }
      pub fn fatal(&self, msg: &str) -> ! {
-         panic!(self.diagnostic().fatal(msg))
+         self.diagnostic().fatal(msg).raise()
      }
      pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
          if is_warning {
              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 {
          // 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,
@@@ -943,7 -919,7 +943,7 @@@ pub fn build_session_(sopts: config::Op
      let host = match Target::search(config::host_triple()) {
          Ok(t) => t,
          Err(e) => {
-             panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
+             span_diagnostic.fatal(&format!("Error loading host specification: {}", e)).raise();
          }
      };
      let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
      let working_dir = match env::current_dir() {
          Ok(dir) => dir,
          Err(e) => {
-             panic!(p_s.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)))
+             p_s.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise()
          }
      };
      let working_dir = file_path_mapping.map_prefix(working_dir);
@@@ -1100,7 -1076,7 +1100,7 @@@ pub fn early_error(output: config::Erro
      };
      let handler = errors::Handler::with_emitter(true, false, emitter);
      handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
-     panic!(errors::FatalError);
+     errors::FatalError.raise();
  }
  
  pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
index db8db16a6c421d6dfd396ac77ddb0c51122f4a18,884d4c7d14b588b3f95375afaf13788c4cc279ac..8afa63a5e9735e113bceac783870cdca3d54d91f
@@@ -11,7 -11,6 +11,7 @@@
  use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
  use back::lto::{self, ModuleBuffer, ThinBuffer};
  use back::link::{self, get_linker, remove};
 +use back::command::Command;
  use back::linker::LinkerInfo;
  use back::symbol_export::ExportedSymbols;
  use base;
@@@ -19,8 -18,8 +19,8 @@@ use consts
  use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
  use rustc::dep_graph::{DepGraph, WorkProductFileKind};
  use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 -use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
 -                             AllPasses, Sanitizer};
 +use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
 +                             AllPasses, Sanitizer, Lto};
  use rustc::session::Session;
  use rustc::util::nodemap::FxHashMap;
  use rustc_back::LinkerFlavor;
@@@ -33,7 -32,7 +33,7 @@@ use CrateInfo
  use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
  use rustc::ty::TyCtxt;
  use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry};
 -use rustc::util::fs::{link_or_copy, rename_or_copy_remove};
 +use rustc::util::fs::{link_or_copy};
  use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
  use errors::emitter::{Emitter};
  use syntax::attr;
@@@ -69,7 -68,8 +69,7 @@@ pub const RELOC_MODEL_ARGS : [(&'stati
      ("ropi-rwpi", llvm::RelocMode::ROPI_RWPI),
  ];
  
 -pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [
 -    ("default", llvm::CodeModel::Default),
 +pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[
      ("small", llvm::CodeModel::Small),
      ("kernel", llvm::CodeModel::Kernel),
      ("medium", llvm::CodeModel::Medium),
@@@ -155,7 -155,7 +155,7 @@@ fn get_llvm_opt_size(optimize: config::
  
  pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
      target_machine_factory(sess)().unwrap_or_else(|err| {
-         panic!(llvm_err(sess.diagnostic(), err))
+         llvm_err(sess.diagnostic(), err).raise()
      })
  }
  
@@@ -170,23 -170,20 +170,23 @@@ pub fn target_machine_factory(sess: &Se
      let ffunction_sections = sess.target.target.options.function_sections;
      let fdata_sections = ffunction_sections;
  
 -    let code_model_arg = match sess.opts.cg.code_model {
 -        Some(ref s) => &s,
 -        None => &sess.target.target.options.code_model,
 -    };
 -
 -    let code_model = match CODE_GEN_MODEL_ARGS.iter().find(
 -        |&&arg| arg.0 == code_model_arg) {
 -        Some(x) => x.1,
 -        _ => {
 -            sess.err(&format!("{:?} is not a valid code model",
 -                              code_model_arg));
 -            sess.abort_if_errors();
 -            bug!();
 +    let code_model_arg = sess.opts.cg.code_model.as_ref().or(
 +        sess.target.target.options.code_model.as_ref(),
 +    );
 +
 +    let code_model = match code_model_arg {
 +        Some(s) => {
 +            match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) {
 +                Some(x) => x.1,
 +                _ => {
 +                    sess.err(&format!("{:?} is not a valid code model",
 +                                      code_model_arg));
 +                    sess.abort_if_errors();
 +                    bug!();
 +                }
 +            }
          }
 +        None => llvm::CodeModel::None,
      };
  
      let singlethread = sess.target.target.options.singlethread;
@@@ -261,7 -258,6 +261,7 @@@ pub struct ModuleConfig 
      // make the object file bitcode. Provides easy compatibility with
      // emscripten's ecc compiler, when used as the linker.
      obj_is_bitcode: bool,
 +    no_integrated_as: bool,
  }
  
  impl ModuleConfig {
              emit_asm: false,
              emit_obj: false,
              obj_is_bitcode: false,
 +            no_integrated_as: false,
  
              no_verify: false,
              no_prepopulate_passes: false,
      }
  }
  
 +/// Assembler name and command used by codegen when no_integrated_as is enabled
 +struct AssemblerCommand {
 +    name: PathBuf,
 +    cmd: Command,
 +}
 +
  /// Additional resources used by optimize_and_codegen (not module specific)
  #[derive(Clone)]
  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,
      // A reference to the TimeGraph so we can register timings. None means that
      // measuring is disabled.
      time_graph: Option<TimeGraph>,
 +    // The assembler command if no_integrated_as option is enabled, None otherwise
 +    assembler_cmd: Option<Arc<AssemblerCommand>>,
  }
  
  impl CodegenContext {
@@@ -588,8 -576,13 +588,8 @@@ fn generate_lto_work(cgcx: &CodegenCont
                   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));
+         .unwrap_or_else(|e| e.raise());
  
      lto_modules.into_iter().map(|module| {
          let cost = module.cost();
@@@ -646,17 -639,13 +646,17 @@@ unsafe fn codegen(cgcx: &CodegenContext
          !cgcx.crate_types.contains(&config::CrateTypeRlib) &&
          mtrans.kind == ModuleKind::Regular;
  
 +    // If we don't have the integrated assembler, then we need to emit asm
 +    // from LLVM and use `gcc` to create the object file.
 +    let asm_to_obj = config.emit_obj && config.no_integrated_as;
 +
      // Change what we write and cleanup based on whether obj files are
      // just llvm bitcode. In that case write bitcode, and possibly
      // delete the bitcode if it wasn't requested. Don't generate the
      // machine code, instead copy the .o file from the .bc
      let write_bc = config.emit_bc || (config.obj_is_bitcode && !asm2wasm);
      let rm_bc = !config.emit_bc && config.obj_is_bitcode && !asm2wasm;
 -    let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm;
 +    let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm && !asm_to_obj;
      let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode && !asm2wasm;
  
      let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
              timeline.record("ir");
          }
  
 -        if config.emit_asm || (asm2wasm && config.emit_obj) {
 +        if config.emit_asm || (asm2wasm && config.emit_obj) || asm_to_obj {
              let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
  
              // We can't use the same module for asm and binary output, because that triggers
              // various errors like invalid IR or broken binaries, so we might have to clone the
              // module to produce the asm output
 -            let llmod = if config.emit_obj {
 +            let llmod = if config.emit_obj && !asm2wasm {
                  llvm::LLVMCloneModule(llmod)
              } else {
                  llmod
                  write_output_file(diag_handler, tm, cpm, llmod, &path,
                                    llvm::FileType::AssemblyFile)
              })?;
 -            if config.emit_obj {
 +            if config.emit_obj && !asm2wasm {
                  llvm::LLVMDisposeModule(llmod);
              }
              timeline.record("asm");
                                    llvm::FileType::ObjectFile)
              })?;
              timeline.record("obj");
 +        } else if asm_to_obj {
 +            let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
 +            run_assembler(cgcx, diag_handler, &assembly, &obj_out);
 +            timeline.record("asm_to_obj");
 +
 +            if !config.emit_asm && !cgcx.save_temps {
 +                drop(fs::remove_file(&assembly));
 +            }
          }
  
          Ok(())
@@@ -860,6 -841,7 +860,6 @@@ pub fn start_async_translation(tcx: TyC
                                 total_cgus: usize)
                                 -> OngoingCrateTranslation {
      let sess = tcx.sess;
 -    let crate_output = tcx.output_filenames(LOCAL_CRATE);
      let crate_name = tcx.crate_name(LOCAL_CRATE);
      let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins");
      let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs,
          subsystem.to_string()
      });
  
 -    let no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
 -        (tcx.sess.target.target.options.no_integrated_as &&
 -         (crate_output.outputs.contains_key(&OutputType::Object) ||
 -          crate_output.outputs.contains_key(&OutputType::Exe)));
      let linker_info = LinkerInfo::new(tcx);
      let crate_info = CrateInfo::new(tcx);
  
 -    let output_types_override = if no_integrated_as {
 -        OutputTypes::new(&[(OutputType::Assembly, None)])
 -    } else {
 -        sess.opts.output_types.clone()
 -    };
 -
      // Figure out what we actually need to build.
      let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone());
      let mut metadata_config = ModuleConfig::new(vec![]);
          allocator_config.emit_bc_compressed = true;
      }
  
 -    for output_type in output_types_override.keys() {
 +    modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
 +        tcx.sess.target.target.options.no_integrated_as;
 +
 +    for output_type in sess.opts.output_types.keys() {
          match *output_type {
              OutputType::Bitcode => { modules_config.emit_bc = true; }
              OutputType::LlvmAssembly => { modules_config.emit_ir = true; }
          metadata,
          windows_subsystem,
          linker_info,
 -        no_integrated_as,
          crate_info,
  
          time_graph,
@@@ -1290,51 -1280,28 +1290,51 @@@ fn execute_work_item(cgcx: &CodegenCont
          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))
              }
          }
      }
@@@ -1410,25 -1377,28 +1410,25 @@@ 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 assembler_cmd = if modules_config.no_integrated_as {
 +        // HACK: currently we use linker (gcc) as our assembler
 +        let (name, mut cmd, _) = get_linker(sess);
 +        cmd.args(&sess.target.target.options.asm_args);
 +        Some(Arc::new(AssemblerCommand {
 +            name,
 +            cmd,
 +        }))
 +    } else {
 +        None
 +    };
 +
      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,
          binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
          debuginfo: tcx.sess.opts.debuginfo,
          wasm_import_memory: wasm_import_memory,
 +        assembler_cmd,
      };
  
      // This is the "main loop" of parallel work happening for parallel codegen.
@@@ -1962,14 -1931,15 +1962,14 @@@ fn spawn_work(cgcx: CodegenContext, wor
      });
  }
  
 -pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
 -    let (pname, mut cmd, _) = get_linker(sess);
 -
 -    for arg in &sess.target.target.options.asm_args {
 -        cmd.arg(arg);
 -    }
 +pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, object: &Path) {
 +    let assembler = cgcx.assembler_cmd
 +        .as_ref()
 +        .expect("cgcx.assembler_cmd is missing?");
  
 -    cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
 -                           .arg(&outputs.temp_path(OutputType::Assembly, None));
 +    let pname = &assembler.name;
 +    let mut cmd = assembler.cmd.clone();
 +    cmd.arg("-c").arg("-o").arg(object).arg(assembly);
      debug!("{:?}", cmd);
  
      match cmd.output() {
                  let mut note = prog.stderr.clone();
                  note.extend_from_slice(&prog.stdout);
  
 -                sess.struct_err(&format!("linking with `{}` failed: {}",
 -                                         pname.display(),
 -                                         prog.status))
 +                handler.struct_err(&format!("linking with `{}` failed: {}",
 +                                            pname.display(),
 +                                            prog.status))
                      .note(&format!("{:?}", &cmd))
                      .note(str::from_utf8(&note[..]).unwrap())
                      .emit();
 -                sess.abort_if_errors();
 +                handler.abort_if_errors();
              }
          },
          Err(e) => {
 -            sess.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
 -            sess.abort_if_errors();
 +            handler.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
 +            handler.abort_if_errors();
          }
      }
  }
@@@ -2163,6 -2133,7 +2163,6 @@@ pub struct OngoingCrateTranslation 
      metadata: EncodedMetadata,
      windows_subsystem: Option<String>,
      linker_info: LinkerInfo,
 -    no_integrated_as: bool,
      crate_info: CrateInfo,
      time_graph: Option<TimeGraph>,
      coordinator_send: Sender<Box<Any + Send>>,
@@@ -2218,6 -2189,26 +2218,6 @@@ impl OngoingCrateTranslation 
              metadata_module: compiled_modules.metadata_module,
          };
  
 -        if self.no_integrated_as {
 -            run_assembler(sess,  &self.output_filenames);
 -
 -            // HACK the linker expects the object file to be named foo.0.o but
 -            // `run_assembler` produces an object named just foo.o. Rename it if we
 -            // are going to build an executable
 -            if sess.opts.output_types.contains_key(&OutputType::Exe) {
 -                let f =  self.output_filenames.path(OutputType::Object);
 -                rename_or_copy_remove(&f,
 -                    f.with_file_name(format!("{}.0.o",
 -                                             f.file_stem().unwrap().to_string_lossy()))).unwrap();
 -            }
 -
 -            // Remove assembly source, unless --save-temps was specified
 -            if !sess.opts.cg.save_temps {
 -                fs::remove_file(&self.output_filenames
 -                                     .temp_path(OutputType::Assembly, None)).unwrap();
 -            }
 -        }
 -
          trans
      }