Skip to content

Commit

Permalink
Auto merge of #32080 - eddyb:transcendent, r=nikomatsakis
Browse files Browse the repository at this point in the history
Refactor call & function handling in trans, enable MIR bootstrap.

Non-Rust and Rust ABIs were combined into a common codepath, which means:
* The ugly `__rust_abi` "clown shoes" shim for C->Rust FFI is gone, fixes #10116.
* Methods, *including virtual ones* support non-Rust ABIs, closes #30235.
* Non-Rust ABIs also pass fat pointers in two arguments; the result should be identical.
* Zero-sized types are never passed as arguments; again, behavior shouldn't change.

Additionally, MIR support for calling intrinsics (through old trans) was implemented.
Alongside assorted fixes, it enabled MIR to launch 🚀 and do a *complete* bootstrap.
To try it yourself, `./configure --enable-orbit` *or* `make RUSTFLAGS="-Z orbit"`.
  • Loading branch information
bors committed Mar 18, 2016
2 parents 2de6ddd + b12dcde commit 235d774
Show file tree
Hide file tree
Showing 155 changed files with 4,601 additions and 6,369 deletions.
3 changes: 3 additions & 0 deletions configure
Expand Up @@ -607,6 +607,7 @@ opt dist-host-only 0 "only install bins for the host architecture"
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
opt llvm-version-check 1 "check if the LLVM version is supported, build anyway"
opt rustbuild 0 "use the rust and cargo based build system"
opt orbit 0 "get MIR where it belongs - everywhere; most importantly, in orbit"

# Optimization and debugging options. These may be overridden by the release channel, etc.
opt_nosave optimize 1 "build optimized rust code"
Expand Down Expand Up @@ -713,6 +714,8 @@ if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTION
if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi

if [ -n "$CFG_ENABLE_ORBIT" ]; then putvar CFG_ENABLE_ORBIT; fi

# A magic value that allows the compiler to use unstable features
# during the bootstrap even when doing so would normally be an error
# because of feature staging or because the build turns on
Expand Down
5 changes: 5 additions & 0 deletions mk/main.mk
Expand Up @@ -134,6 +134,11 @@ ifdef CFG_ENABLE_DEBUGINFO
CFG_RUSTC_FLAGS += -g
endif

ifdef CFG_ENABLE_ORBIT
$(info cfg: launching MIR (CFG_ENABLE_ORBIT))
CFG_RUSTC_FLAGS += -Z orbit
endif

ifdef SAVE_TEMPS
CFG_RUSTC_FLAGS += --save-temps
endif
Expand Down
13 changes: 10 additions & 3 deletions src/compiletest/header.rs
Expand Up @@ -31,6 +31,8 @@ pub struct TestProps {
pub pp_exact: Option<PathBuf>,
// Modules from aux directory that should be compiled
pub aux_builds: Vec<String> ,
// Environment settings to use for compiling
pub rustc_env: Vec<(String,String)> ,
// Environment settings to use during execution
pub exec_env: Vec<(String,String)> ,
// Lines to check if they appear in the expected debugger output
Expand Down Expand Up @@ -77,6 +79,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
pp_exact: pp_exact,
aux_builds: aux_builds,
revisions: vec![],
rustc_env: vec![],
exec_env: exec_env,
check_lines: check_lines,
build_aux_docs: build_aux_docs,
Expand Down Expand Up @@ -153,10 +156,14 @@ pub fn load_props_into(props: &mut TestProps, testfile: &Path, cfg: Option<&str>
props.aux_builds.push(ab);
}

if let Some(ee) = parse_exec_env(ln) {
if let Some(ee) = parse_env(ln, "exec-env") {
props.exec_env.push(ee);
}

if let Some(ee) = parse_env(ln, "rustc-env") {
props.rustc_env.push(ee);
}

if let Some(cl) = parse_check_line(ln) {
props.check_lines.push(cl);
}
Expand Down Expand Up @@ -372,8 +379,8 @@ fn parse_pretty_compare_only(line: &str) -> bool {
parse_name_directive(line, "pretty-compare-only")
}

fn parse_exec_env(line: &str) -> Option<(String, String)> {
parse_name_value_directive(line, "exec-env").map(|nv| {
fn parse_env(line: &str, name: &str) -> Option<(String, String)> {
parse_name_value_directive(line, name).map(|nv| {
// nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv
.splitn(2, '=')
Expand Down
26 changes: 21 additions & 5 deletions src/compiletest/runtest.rs
Expand Up @@ -863,12 +863,28 @@ fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
"-g".to_owned(),
"--debuginfo".to_owned()
];
let new_options =
let mut new_options =
split_maybe_args(options).into_iter()
.filter(|x| !options_to_remove.contains(x))
.collect::<Vec<String>>()
.join(" ");
Some(new_options)
.collect::<Vec<String>>();

let mut i = 0;
while i + 1 < new_options.len() {
if new_options[i] == "-Z" {
// FIXME #31005 MIR missing debuginfo currently.
if new_options[i + 1] == "orbit" {
// Remove "-Z" and "orbit".
new_options.remove(i);
new_options.remove(i);
continue;
}
// Always skip over -Z's argument.
i += 1;
}
i += 1;
}

Some(new_options.join(" "))
}

fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) {
Expand Down Expand Up @@ -1386,7 +1402,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
compose_and_run(config,
testpaths,
args,
Vec::new(),
props.rustc_env.clone(),
&config.compile_lib_path,
Some(aux_dir.to_str().unwrap()),
input)
Expand Down
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Expand Up @@ -72,6 +72,7 @@
#![feature(reflect)]
#![feature(unwind_attributes)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(staged_api)]
#![feature(unboxed_closures)]

Expand Down
3 changes: 3 additions & 0 deletions src/libcore/num/mod.rs
Expand Up @@ -1008,6 +1008,7 @@ macro_rules! int_impl {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg_attr(not(stage0), rustc_no_mir)] // FIXME #29769 MIR overflow checking is TBD.
pub fn pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc = Self::one();
Expand Down Expand Up @@ -1049,6 +1050,7 @@ macro_rules! int_impl {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg_attr(not(stage0), rustc_no_mir)] // FIXME #29769 MIR overflow checking is TBD.
pub fn abs(self) -> Self {
if self.is_negative() {
// Note that the #[inline] above means that the overflow
Expand Down Expand Up @@ -2013,6 +2015,7 @@ macro_rules! uint_impl {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg_attr(not(stage0), rustc_no_mir)] // FIXME #29769 MIR overflow checking is TBD.
pub fn pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc = Self::one();
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/front/map/mod.rs
Expand Up @@ -22,6 +22,7 @@ use middle::def_id::DefId;

use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID};
use syntax::attr::ThinAttributesExt;
use syntax::codemap::{Span, Spanned};
use syntax::parse::token;

Expand Down Expand Up @@ -718,6 +719,8 @@ impl<'ast> Map<'ast> {
Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]),
Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]),
Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]),
Some(NodeExpr(ref e)) => Some(e.attrs.as_attr_slice()),
Some(NodeStmt(ref s)) => Some(s.node.attrs()),
// unit/tuple structs take the attributes straight from
// the struct definition.
Some(NodeStructCtor(_)) => {
Expand Down
1 change: 0 additions & 1 deletion src/librustc/lib.rs
Expand Up @@ -73,7 +73,6 @@ mod macros;
pub mod diagnostics;

pub mod back {
pub use rustc_back::abi;
pub use rustc_back::rpath;
pub use rustc_back::svh;
}
Expand Down
17 changes: 4 additions & 13 deletions src/librustc/middle/cfg/construct.rs
Expand Up @@ -354,19 +354,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
self.straightline(expr, pred, Some(&**e).into_iter())
}

hir::ExprInlineAsm(ref inline_asm) => {
let inputs = inline_asm.inputs.iter();
let outputs = inline_asm.outputs.iter();
let post_inputs = self.exprs(inputs.map(|a| {
debug!("cfg::construct InlineAsm id:{} input:{:?}", expr.id, a);
let &(_, ref expr) = a;
&**expr
}), pred);
let post_outputs = self.exprs(outputs.map(|a| {
debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a);
&*a.expr
}), post_inputs);
self.add_ast_node(expr.id, &[post_outputs])
hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
let post_outputs = self.exprs(outputs.iter().map(|e| &**e), pred);
let post_inputs = self.exprs(inputs.iter().map(|e| &**e), post_outputs);
self.add_ast_node(expr.id, &[post_inputs])
}

hir::ExprClosure(..) |
Expand Down
11 changes: 5 additions & 6 deletions src/librustc/middle/check_match.rs
Expand Up @@ -475,9 +475,9 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
match def {
Some(Def::AssociatedConst(did)) |
Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
Some(pat.id), None) {
Some((const_expr, _const_ty)) => {
Some(Def::Const(did)) => {
let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {

if let Some(ref mut renaming_map) = self.renaming_map {
Expand All @@ -487,14 +487,13 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {

new_pat
})
}
None => {
} else {
self.failed = true;
span_err!(self.tcx.sess, pat.span, E0158,
"statics cannot be referenced in patterns");
pat
}
},
}
_ => noop_fold_pat(pat, self)
}
}
Expand Down
67 changes: 25 additions & 42 deletions src/librustc/middle/const_eval.rs
Expand Up @@ -19,7 +19,6 @@ use front::map::blocks::FnLikeNode;
use middle::cstore::{self, CrateStore, InlinedItem};
use middle::{infer, subst, traits};
use middle::def::Def;
use middle::subst::Subst;
use middle::def_id::DefId;
use middle::pat_util::def_to_path;
use middle::ty::{self, Ty, TyCtxt};
Expand Down Expand Up @@ -89,16 +88,13 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::TyCtxt,
}

/// * `def_id` is the id of the constant.
/// * `maybe_ref_id` is the id of the expr referencing the constant.
/// * `param_substs` is the monomorphization substitution for the expression.
/// * `substs` is the monomorphized substitutions for the expression.
///
/// `maybe_ref_id` and `param_substs` are optional and are used for
/// finding substitutions in associated constants. This generally
/// happens in late/trans const evaluation.
/// `substs` is optional and is used for associated constants.
/// This generally happens in late/trans const evaluation.
pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
def_id: DefId,
maybe_ref_id: Option<ast::NodeId>,
param_substs: Option<&'tcx subst::Substs<'tcx>>)
substs: Option<subst::Substs<'tcx>>)
-> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.map.find(node_id) {
Expand All @@ -111,28 +107,20 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
},
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
hir::ConstTraitItem(_, _) => {
match maybe_ref_id {
// If we have a trait item, and we know the expression
// that's the source of the obligation to resolve it,
if let Some(substs) = substs {
// If we have a trait item and the substitutions for it,
// `resolve_trait_associated_const` will select an impl
// or the default.
Some(ref_id) => {
let trait_id = tcx.trait_of_item(def_id)
.unwrap();
let mut substs = tcx.node_id_item_substs(ref_id)
.substs;
if let Some(param_substs) = param_substs {
substs = substs.subst(tcx, param_substs);
}
resolve_trait_associated_const(tcx, ti, trait_id, substs)
}
let trait_id = tcx.trait_of_item(def_id).unwrap();
resolve_trait_associated_const(tcx, ti, trait_id, substs)
} else {
// Technically, without knowing anything about the
// expression that generates the obligation, we could
// still return the default if there is one. However,
// it's safer to return `None` than to return some value
// that may differ from what you would get from
// correctly selecting an impl.
None => None
None
}
}
_ => None
Expand All @@ -153,7 +141,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
}
None => {}
}
let mut used_ref_id = false;
let mut used_substs = false;
let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
hir::ItemConst(ref ty, ref const_expr) => {
Expand All @@ -163,21 +151,15 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
},
cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node {
hir::ConstTraitItem(_, _) => {
used_ref_id = true;
match maybe_ref_id {
used_substs = true;
if let Some(substs) = substs {
// As mentioned in the comments above for in-crate
// constants, we only try to find the expression for
// a trait-associated const if the caller gives us
// the expression that refers to it.
Some(ref_id) => {
let mut substs = tcx.node_id_item_substs(ref_id)
.substs;
if let Some(param_substs) = param_substs {
substs = substs.subst(tcx, param_substs);
}
resolve_trait_associated_const(tcx, ti, trait_id, substs)
}
None => None
// the substitutions for the reference to it.
resolve_trait_associated_const(tcx, ti, trait_id, substs)
} else {
None
}
}
_ => None
Expand All @@ -190,10 +172,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
},
_ => None
};
// If we used the reference expression, particularly to choose an impl
// If we used the substitutions, particularly to choose an impl
// of a trait-associated const, don't cache that, because the next
// lookup with the same def_id may yield a different result.
if !used_ref_id {
if !used_substs {
tcx.extern_const_statics
.borrow_mut()
.insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
Expand Down Expand Up @@ -389,7 +371,8 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
PatKind::Path(path.clone()),
Some(Def::Const(def_id)) |
Some(Def::AssociatedConst(def_id)) => {
let (expr, _ty) = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
let substs = Some(tcx.node_id_item_substs(expr.id).substs);
let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
return const_expr_to_pat(tcx, expr, span);
},
_ => unreachable!(),
Expand Down Expand Up @@ -788,12 +771,12 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
match opt_def {
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {
let maybe_ref_id = if let ExprTypeChecked = ty_hint {
Some(e.id)
let substs = if let ExprTypeChecked = ty_hint {
Some(tcx.node_id_item_substs(e.id).substs)
} else {
None
};
if let Some((e, ty)) = lookup_const_by_id(tcx, def_id, maybe_ref_id, None) {
if let Some((e, ty)) = lookup_const_by_id(tcx, def_id, substs) {
let item_hint = match ty {
Some(ty) => ty_hint.checked_or(ty),
None => ty_hint,
Expand Down Expand Up @@ -1077,7 +1060,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
traits::VtableImpl(ref impl_data) => {
match tcx.associated_consts(impl_data.impl_def_id)
.iter().find(|ic| ic.name == ti.name) {
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None),
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
None => match ti.node {
hir::ConstTraitItem(ref ty, Some(ref expr)) => {
Some((&*expr, ast_ty_to_prim_ty(tcx, ty)))
Expand Down

0 comments on commit 235d774

Please sign in to comment.