Auto merge of #41102 - frewsxcv:rollup, r=frewsxcv

Rollup of 5 pull requests

- Successful merges: #40908, #41011, #41026, #41037, #41050
- Failed merges:
This commit is contained in:
bors 2017-04-06 06:07:42 +00:00
commit e5e92753cc
74 changed files with 286 additions and 174 deletions

View File

@ -600,16 +600,19 @@ def bootstrap():
def main():
start_time = time()
help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
try:
bootstrap()
print("Build completed successfully in %s" % format_build_time(time() - start_time))
if not help_triggered:
print("Build completed successfully in %s" % format_build_time(time() - start_time))
except (SystemExit, KeyboardInterrupt) as e:
if hasattr(e, 'code') and isinstance(e.code, int):
exit_code = e.code
else:
exit_code = 1
print(e)
print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time))
if not help_triggered:
print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time))
sys.exit(exit_code)
if __name__ == '__main__':

View File

@ -44,26 +44,25 @@ pub fn clean(build: &Build) {
}
fn rm_rf(path: &Path) {
if !path.exists() {
return
}
if path.is_file() {
return do_op(path, "remove file", |p| fs::remove_file(p));
}
match path.symlink_metadata() {
Err(e) => {
if e.kind() == ErrorKind::NotFound {
return;
}
panic!("failed to get metadata for file {}: {}", path.display(), e);
},
Ok(metadata) => {
if metadata.file_type().is_file() || metadata.file_type().is_symlink() {
do_op(path, "remove file", |p| fs::remove_file(p));
return;
}
for file in t!(fs::read_dir(path)) {
let file = t!(file).path();
if file.is_dir() {
rm_rf(&file);
} else {
// On windows we can't remove a readonly file, and git will
// often clone files as readonly. As a result, we have some
// special logic to remove readonly files on windows.
do_op(&file, "remove file", |p| fs::remove_file(p));
}
}
do_op(path, "remove dir", |p| fs::remove_dir(p));
for file in t!(fs::read_dir(path)) {
rm_rf(&t!(file).path());
}
do_op(path, "remove dir", |p| fs::remove_dir(p));
},
};
}
fn do_op<F>(path: &Path, desc: &str, mut f: F)
@ -71,9 +70,12 @@ fn do_op<F>(path: &Path, desc: &str, mut f: F)
{
match f(path) {
Ok(()) => {}
// On windows we can't remove a readonly file, and git will often clone files as readonly.
// As a result, we have some special logic to remove readonly files on windows.
// This is also the reason that we can't use things like fs::remove_dir_all().
Err(ref e) if cfg!(windows) &&
e.kind() == ErrorKind::PermissionDenied => {
let mut p = t!(path.metadata()).permissions();
let mut p = t!(path.symlink_metadata()).permissions();
p.set_readonly(false);
t!(fs::set_permissions(path, p));
f(path).unwrap_or_else(|e| {

View File

@ -18,7 +18,7 @@
use std::path::PathBuf;
use std::process;
use getopts::{Matches, Options};
use getopts::Options;
use Build;
use config::Config;
@ -75,7 +75,22 @@ pub enum Subcommand {
impl Flags {
pub fn parse(args: &[String]) -> Flags {
let mut extra_help = String::new();
let mut subcommand_help = format!("\
Usage: x.py <subcommand> [options] [<paths>...]
Subcommands:
build Compile either the compiler or libraries
test Build and run some test suites
bench Build and run some benchmarks
doc Build documentation
clean Clean out build directories
dist Build and/or install distribution artifacts
To learn more about a subcommand, run `./x.py <subcommand> -h`");
let mut opts = Options::new();
// Options common to all subcommands
opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
opts.optflag("i", "incremental", "use incremental compilation");
opts.optopt("", "config", "TOML configuration file for build", "FILE");
@ -89,21 +104,83 @@ pub fn parse(args: &[String]) -> Flags {
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("h", "help", "print this help message");
let usage = |n, opts: &Options| -> ! {
let command = args.get(0).map(|s| &**s);
let brief = format!("Usage: x.py {} [options] [<args>...]",
command.unwrap_or("<command>"));
// fn usage()
let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
println!("{}", opts.usage(subcommand_help));
if !extra_help.is_empty() {
println!("{}", extra_help);
}
process::exit(exit_code);
};
println!("{}", opts.usage(&brief));
match command {
Some("build") => {
println!("\
// We can't use getopt to parse the options until we have completed specifying which
// options are valid, but under the current implementation, some options are conditional on
// the subcommand. Therefore we must manually identify the subcommand first, so that we can
// complete the definition of the options. Then we can use the getopt::Matches object from
// there on out.
let mut possible_subcommands = args.iter().collect::<Vec<_>>();
possible_subcommands.retain(|&s|
(s == "build")
|| (s == "test")
|| (s == "bench")
|| (s == "doc")
|| (s == "clean")
|| (s == "dist"));
let subcommand = match possible_subcommands.first() {
Some(s) => s,
None => {
// No subcommand -- show the general usage and subcommand help
println!("{}\n", subcommand_help);
process::exit(0);
}
};
// Some subcommands get extra options
match subcommand.as_str() {
"test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"dist" => { opts.optflag("", "install", "run installer as well"); },
_ => { },
};
// Done specifying what options are possible, so do the getopts parsing
let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
// Invalid argument/option format
println!("\n{}\n", e);
usage(1, &opts, &subcommand_help, &extra_help);
});
// Extra sanity check to make sure we didn't hit this crazy corner case:
//
// ./x.py --frobulate clean build
// ^-- option ^ ^- actual subcommand
// \_ arg to option could be mistaken as subcommand
let mut pass_sanity_check = true;
match matches.free.get(0) {
Some(check_subcommand) => {
if &check_subcommand != subcommand {
pass_sanity_check = false;
}
},
None => {
pass_sanity_check = false;
}
}
if !pass_sanity_check {
println!("{}\n", subcommand_help);
println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
You may need to move some options to after the subcommand.\n");
process::exit(1);
}
// Extra help text for some commands
match subcommand.as_str() {
"build" => {
subcommand_help.push_str("\n
Arguments:
This subcommand accepts a number of positional arguments of directories to
the crates and/or artifacts to compile. For example:
This subcommand accepts a number of paths to directories to the crates
and/or artifacts to compile. For example:
./x.py build src/libcore
./x.py build src/libproc_macro
./x.py build src/libcore src/libproc_macro
./x.py build src/libstd --stage 1
If no arguments are passed then the complete artifacts for that stage are
@ -114,15 +191,13 @@ pub fn parse(args: &[String]) -> Flags {
For a quick build with a usable compile, you can pass:
./x.py build --stage 1 src/libtest
");
}
Some("test") => {
println!("\
./x.py build --stage 1 src/libtest");
}
"test" => {
subcommand_help.push_str("\n
Arguments:
This subcommand accepts a number of positional arguments of directories to
tests that should be compiled and run. For example:
This subcommand accepts a number of paths to directories to tests that
should be compiled and run. For example:
./x.py test src/test/run-pass
./x.py test src/libstd --test-args hash_map
@ -132,139 +207,90 @@ pub fn parse(args: &[String]) -> Flags {
compiled and tested.
./x.py test
./x.py test --stage 1
");
}
Some("doc") => {
println!("\
./x.py test --stage 1");
}
"doc" => {
subcommand_help.push_str("\n
Arguments:
This subcommand accepts a number of positional arguments of directories of
documentation to build. For example:
This subcommand accepts a number of paths to directories of documentation
to build. For example:
./x.py doc src/doc/book
./x.py doc src/doc/nomicon
./x.py doc src/libstd
./x.py doc src/doc/book src/libstd
If no arguments are passed then everything is documented:
./x.py doc
./x.py doc --stage 1
");
}
_ => {}
./x.py doc --stage 1");
}
if let Some(command) = command {
if command == "build" ||
command == "dist" ||
command == "doc" ||
command == "test" ||
command == "bench" ||
command == "clean" {
println!("Available invocations:");
if args.iter().any(|a| a == "-v") {
let flags = Flags::parse(&["build".to_string()]);
let mut config = Config::default();
config.build = flags.build.clone();
let mut build = Build::new(flags, config);
metadata::build(&mut build);
step::build_rules(&build).print_help(command);
} else {
println!(" ... elided, run `./x.py {} -h -v` to see",
command);
}
println!("");
}
}
println!("\
Subcommands:
build Compile either the compiler or libraries
test Build and run some test suites
bench Build and run some benchmarks
doc Build documentation
clean Clean out build directories
dist Build and/or install distribution artifacts
To learn more about a subcommand, run `./x.py <command> -h`
");
process::exit(n);
_ => { }
};
if args.len() == 0 {
println!("a command must be passed");
usage(1, &opts);
}
let parse = |opts: &Options| {
let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
println!("failed to parse options: {}", e);
usage(1, opts);
});
if m.opt_present("h") {
usage(0, opts);
}
return m
};
// Get any optional paths which occur after the subcommand
let cwd = t!(env::current_dir());
let remaining_as_path = |m: &Matches| {
m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
};
let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();
let m: Matches;
let cmd = match &args[0][..] {
"build" => {
m = parse(&opts);
Subcommand::Build { paths: remaining_as_path(&m) }
// All subcommands can have an optional "Available paths" section
if matches.opt_present("verbose") {
let flags = Flags::parse(&["build".to_string()]);
let mut config = Config::default();
config.build = flags.build.clone();
let mut build = Build::new(flags, config);
metadata::build(&mut build);
let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
if maybe_rules_help.is_some() {
extra_help.push_str(maybe_rules_help.unwrap().as_str());
}
"doc" => {
m = parse(&opts);
Subcommand::Doc { paths: remaining_as_path(&m) }
} else {
extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
subcommand).as_str());
}
// User passed in -h/--help?
if matches.opt_present("help") {
usage(0, &opts, &subcommand_help, &extra_help);
}
let cmd = match subcommand.as_str() {
"build" => {
Subcommand::Build { paths: paths }
}
"test" => {
opts.optmulti("", "test-args", "extra arguments", "ARGS");
m = parse(&opts);
Subcommand::Test {
paths: remaining_as_path(&m),
test_args: m.opt_strs("test-args"),
paths: paths,
test_args: matches.opt_strs("test-args"),
}
}
"bench" => {
opts.optmulti("", "test-args", "extra arguments", "ARGS");
m = parse(&opts);
Subcommand::Bench {
paths: remaining_as_path(&m),
test_args: m.opt_strs("test-args"),
paths: paths,
test_args: matches.opt_strs("test-args"),
}
}
"doc" => {
Subcommand::Doc { paths: paths }
}
"clean" => {
m = parse(&opts);
if m.free.len() > 0 {
println!("clean takes no arguments");
usage(1, &opts);
if paths.len() > 0 {
println!("\nclean takes no arguments\n");
usage(1, &opts, &subcommand_help, &extra_help);
}
Subcommand::Clean
}
"dist" => {
opts.optflag("", "install", "run installer as well");
m = parse(&opts);
Subcommand::Dist {
paths: remaining_as_path(&m),
install: m.opt_present("install"),
paths: paths,
install: matches.opt_present("install"),
}
}
"--help" => usage(0, &opts),
cmd => {
println!("unknown command: {}", cmd);
usage(1, &opts);
_ => {
usage(1, &opts, &subcommand_help, &extra_help);
}
};
let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
if fs::metadata("config.toml").is_ok() {
Some(PathBuf::from("config.toml"))
} else {
@ -272,31 +298,29 @@ pub fn parse(args: &[String]) -> Flags {
}
});
let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());
let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());
let incremental = m.opt_present("i");
if incremental {
if matches.opt_present("incremental") {
if stage.is_none() {
stage = Some(1);
}
}
Flags {
verbose: m.opt_count("v"),
verbose: matches.opt_count("verbose"),
stage: stage,
on_fail: m.opt_str("on-fail"),
keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
build: m.opt_str("build").unwrap_or_else(|| {
on_fail: matches.opt_str("on-fail"),
keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
build: matches.opt_str("build").unwrap_or_else(|| {
env::var("BUILD").unwrap()
}),
host: split(m.opt_strs("host")),
target: split(m.opt_strs("target")),
host: split(matches.opt_strs("host")),
target: split(matches.opt_strs("target")),
config: cfg_file,
src: m.opt_str("src").map(PathBuf::from),
jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
src: matches.opt_str("src").map(PathBuf::from),
jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
cmd: cmd,
incremental: incremental,
incremental: matches.opt_present("incremental"),
}
}
}

View File

@ -978,26 +978,25 @@ fn verify(&self) {
}
}
pub fn print_help(&self, command: &str) {
pub fn get_help(&self, command: &str) -> Option<String> {
let kind = match command {
"build" => Kind::Build,
"doc" => Kind::Doc,
"test" => Kind::Test,
"bench" => Kind::Bench,
"dist" => Kind::Dist,
_ => return,
_ => return None,
};
let rules = self.rules.values().filter(|r| r.kind == kind);
let rules = rules.filter(|r| !r.path.contains("nowhere"));
let mut rules = rules.collect::<Vec<_>>();
rules.sort_by_key(|r| r.path);
println!("Available paths:\n");
let mut help_string = String::from("Available paths:\n");
for rule in rules {
print!(" ./x.py {} {}", command, rule.path);
println!("");
help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str());
}
Some(help_string)
}
/// Construct the top-level build steps that we're going to be executing,

View File

@ -13,8 +13,8 @@ core = { path = "../libcore" }
std_unicode = { path = "../libstd_unicode" }
[[test]]
name = "collectionstest"
path = "../libcollectionstest/lib.rs"
name = "collectionstests"
path = "../libcollections/tests/lib.rs"
[[bench]]
name = "collectionsbenches"

View File

@ -10,8 +10,8 @@ test = false
bench = false
[[test]]
name = "coretest"
path = "../libcoretest/lib.rs"
name = "coretests"
path = "../libcore/tests/lib.rs"
[[bench]]
name = "corebenches"

View File

@ -19,7 +19,7 @@
//! inputs, but we don't do so to avoid the code bloat. Each bignum is still
//! tracked for the actual usages, so it normally doesn't matter.
// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
// This module is only for dec2flt and flt2dec, and only public because of coretests.
// It is not intended to ever be stabilized.
#![doc(hidden)]
#![unstable(feature = "core_private_bignum",

View File

@ -10,7 +10,7 @@
//! Extended precision "soft float", for internal use only.
// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
// This module is only for dec2flt and flt2dec, and only public because of coretests.
// It is not intended to ever be stabilized.
#![doc(hidden)]
#![unstable(feature = "core_private_diy_float",

View File

@ -118,7 +118,7 @@
string from resulting `Part`s itself.
All algorithms and formatting functions are accompanied by extensive tests
in `coretest::num::flt2dec` module. It also shows how to use individual
in `coretests::num::flt2dec` module. It also shows how to use individual
functions.
*/

View File

@ -90,7 +90,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
mod wrapping;
// All these modules are technically private and only exposed for libcoretest:
// All these modules are technically private and only exposed for coretests:
pub mod flt2dec;
pub mod dec2flt;
pub mod bignum;

View File

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// All `str` tests live in libcollectiontest::str
// All `str` tests live in collectionstests::str

View File

@ -222,8 +222,10 @@ fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>)
let name = unwrap_or!(attrs[i].name(), continue);
if name == "derive" {
let result = attrs[i].parse_list(&self.session.parse_sess,
|parser| parser.parse_path(PathStyle::Mod));
let result = attrs[i].parse_list(&self.session.parse_sess, |parser| {
parser.parse_path_allowing_meta(PathStyle::Mod)
});
let mut traits = match result {
Ok(traits) => traits,
Err(mut e) => {

View File

@ -762,7 +762,6 @@ fn get_personality_slot(&mut self, bcx: &Builder<'a, 'tcx>) -> ValueRef {
let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
let slot = bcx.alloca(llretty, "personalityslot");
self.llpersonalityslot = Some(slot);
Lifetime::Start.call(bcx, slot);
slot
}
}
@ -794,6 +793,7 @@ fn landing_pad_uncached(&mut self, target_bb: BasicBlockRef) -> BasicBlockRef {
let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.llfn);
bcx.set_cleanup(llretval);
let slot = self.get_personality_slot(&bcx);
Lifetime::Start.call(&bcx, slot);
bcx.store(llretval, slot, None);
bcx.br(target_bb);
bcx.llbb()

View File

@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
return true;
}
match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
match attr.parse_list(cx.parse_sess,
|parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
Ok(ref traits) if traits.is_empty() => {
cx.span_warn(attr.span, "empty trait list in `derive`");
false

View File

@ -1767,6 +1767,26 @@ pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
})
}
/// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat.
/// This is used when parsing derive macro paths in `#[derive]` attributes.
pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
let meta_ident = match self.token {
token::Interpolated(ref nt) => match **nt {
token::NtMeta(ref meta) => match meta.node {
ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)),
_ => None,
},
_ => None,
},
_ => None,
};
if let Some(ident) = meta_ident {
self.bump();
return Ok(ast::Path::from_ident(self.prev_span, ident));
}
self.parse_path(mode)
}
/// Examples:
/// - `a::b<T,U>::c<V,W>`
/// - `a::b<T,U>::c(V) -> W`

View File

@ -0,0 +1,41 @@
// Copyright 2017 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.
// ignore-msvc
// compile-flags: -O -C no-prepopulate-passes
#![crate_type="lib"]
struct S;
impl Drop for S {
fn drop(&mut self) {
}
}
fn might_unwind() {
}
// CHECK-LABEL: @test
#[no_mangle]
pub fn test() {
let _s = S;
// Check that the personality slot alloca gets a lifetime start in each cleanup block, not just
// in the first one.
// CHECK-LABEL: cleanup:
// CHECK: bitcast{{.*}}personalityslot
// CHECK-NEXT: call void @llvm.lifetime.start
// CHECK-LABEL: cleanup1:
// CHECK: bitcast{{.*}}personalityslot
// CHECK-NEXT: call void @llvm.lifetime.start
might_unwind();
might_unwind();
}

View File

@ -0,0 +1,20 @@
// Copyright 2017 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.
macro_rules! m {
($i:meta) => {
#[derive($i)]
struct S;
}
}
m!(Clone);
fn main() {}

View File

@ -75,7 +75,7 @@
"src/libtest", // Probably should defer to unstable std::sys APIs
// std testing crates, ok for now at least
"src/libcoretest",
"src/libcore/tests",
// non-std crates
"src/test",