diff options
Diffstat (limited to 'src')
55 files changed, 914 insertions, 331 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7b0a5d6b6df..33de8fd0107 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -10,6 +10,7 @@ import argparse import contextlib +import datetime import hashlib import os import shutil @@ -18,6 +19,8 @@ import sys import tarfile import tempfile +from time import time + def get(url, path, verbose=False): sha_url = url + ".sha256" @@ -118,6 +121,9 @@ def stage0_data(rust_root): data[a] = b return data +def format_build_time(duration): + return str(datetime.timedelta(seconds=int(duration))) + class RustBuild: def download_stage0(self): cache_dst = os.path.join(self.build_dir, "cache") @@ -265,7 +271,7 @@ class RustBuild: try: ostype = subprocess.check_output(['uname', '-s']).strip() cputype = subprocess.check_output(['uname', '-m']).strip() - except subprocess.CalledProcessError: + except (subprocess.CalledProcessError, WindowsError): if sys.platform == 'win32': return 'x86_64-pc-windows-msvc' err = "uname not found" @@ -372,6 +378,8 @@ def main(): rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) rb._cargo_channel, rb._cargo_date = data['cargo'].split('-', 1) + start_time = time() + # Fetch/build the bootstrap rb.build = rb.build_triple() rb.download_stage0() @@ -390,5 +398,9 @@ def main(): env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) rb.run(args, env) + end_time = time() + + print("Build completed in %s" % format_build_time(end_time - start_time)) + if __name__ == '__main__': main() diff --git a/src/bootstrap/build/cc.rs b/src/bootstrap/build/cc.rs index 7eb50b8b86d..ff0941a97dc 100644 --- a/src/bootstrap/build/cc.rs +++ b/src/bootstrap/build/cc.rs @@ -90,6 +90,7 @@ fn set_compiler(cfg: &mut gcc::Config, // compiler already takes into account the triple in question. t if t.contains("android") => { if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) { + let target = target.replace("armv7", "arm"); let compiler = format!("{}-{}", target, gnu_compiler); cfg.compiler(ndk.join("bin").join(compiler)); } diff --git a/src/bootstrap/build/check.rs b/src/bootstrap/build/check.rs index 154d9556fd7..0a096f8e4de 100644 --- a/src/bootstrap/build/check.rs +++ b/src/bootstrap/build/check.rs @@ -23,6 +23,9 @@ use build_helper::output; use bootstrap::{dylib_path, dylib_path_var}; use build::{Build, Compiler, Mode}; +use build::util; + +const ADB_TEST_DIR: &'static str = "/data/tmp"; /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler. /// @@ -88,6 +91,7 @@ pub fn compiletest(build: &Build, target: &str, mode: &str, suite: &str) { + println!("Check compiletest {} ({} -> {})", suite, compiler.host, target); let mut cmd = build.tool_cmd(compiler, "compiletest"); // compiletest currently has... a lot of arguments, so let's just pass all @@ -105,21 +109,23 @@ pub fn compiletest(build: &Build, cmd.arg("--host").arg(compiler.host); cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build)); - let mut flags = format!("-Crpath"); + let mut flags = vec!["-Crpath".to_string()]; if build.config.rust_optimize_tests { - flags.push_str(" -O"); + flags.push("-O".to_string()); } if build.config.rust_debuginfo_tests { - flags.push_str(" -g"); + flags.push("-g".to_string()); } - cmd.arg("--host-rustcflags").arg(&flags); - - let linkflag = format!("-Lnative={}", build.test_helpers_out(target).display()); - cmd.arg("--target-rustcflags").arg(format!("{} {}", flags, linkflag)); + let mut hostflags = build.rustc_flags(&compiler.host); + hostflags.extend(flags.clone()); + cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); - // FIXME: needs android support - cmd.arg("--android-cross-path").arg(""); + let mut targetflags = build.rustc_flags(&target); + targetflags.extend(flags); + targetflags.push(format!("-Lnative={}", + build.test_helpers_out(target).display())); + cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); // FIXME: CFG_PYTHON should probably be detected more robustly elsewhere let python_default = "python"; @@ -180,6 +186,16 @@ pub fn compiletest(build: &Build, } build.add_bootstrap_key(compiler, &mut cmd); + cmd.arg("--adb-path").arg("adb"); + cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); + if target.contains("android") { + // Assume that cc for this target comes from the android sysroot + cmd.arg("--android-cross-path") + .arg(build.cc(target).parent().unwrap().parent().unwrap()); + } else { + cmd.arg("--android-cross-path").arg(""); + } + build.run(&mut cmd); } @@ -302,7 +318,97 @@ pub fn krate(build: &Build, let mut dylib_path = dylib_path(); dylib_path.insert(0, build.sysroot_libdir(compiler, target)); cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); - cargo.args(&build.flags.args); - build.run(&mut cargo); + if target.contains("android") { + build.run(cargo.arg("--no-run")); + krate_android(build, compiler, target, mode); + } else { + cargo.args(&build.flags.args); + build.run(&mut cargo); + } +} + +fn krate_android(build: &Build, + compiler: &Compiler, + target: &str, + mode: Mode) { + let mut tests = Vec::new(); + let out_dir = build.cargo_out(compiler, mode, target); + find_tests(&out_dir, target, &mut tests); + find_tests(&out_dir.join("deps"), target, &mut tests); + + for test in tests { + build.run(Command::new("adb").arg("push").arg(&test).arg(ADB_TEST_DIR)); + + let test_file_name = test.file_name().unwrap().to_string_lossy(); + let log = format!("{}/check-stage{}-T-{}-H-{}-{}.log", + ADB_TEST_DIR, + compiler.stage, + target, + compiler.host, + test_file_name); + let program = format!("(cd {dir}; \ + LD_LIBRARY_PATH=./{target} ./{test} \ + --logfile {log} \ + {args})", + dir = ADB_TEST_DIR, + target = target, + test = test_file_name, + log = log, + args = build.flags.args.join(" ")); + + let output = output(Command::new("adb").arg("shell").arg(&program)); + println!("{}", output); + build.run(Command::new("adb") + .arg("pull") + .arg(&log) + .arg(build.out.join("tmp"))); + build.run(Command::new("adb").arg("shell").arg("rm").arg(&log)); + if !output.contains("result: ok") { + panic!("some tests failed"); + } + } +} + +fn find_tests(dir: &Path, + target: &str, + dst: &mut Vec<PathBuf>) { + for e in t!(dir.read_dir()).map(|e| t!(e)) { + let file_type = t!(e.file_type()); + if !file_type.is_file() { + continue + } + let filename = e.file_name().into_string().unwrap(); + if (target.contains("windows") && filename.ends_with(".exe")) || + (!target.contains("windows") && !filename.contains(".")) { + dst.push(e.path()); + } + } +} + +pub fn android_copy_libs(build: &Build, + compiler: &Compiler, + target: &str) { + println!("Android copy libs to emulator ({})", target); + build.run(Command::new("adb").arg("remount")); + build.run(Command::new("adb").args(&["shell", "rm", "-r", ADB_TEST_DIR])); + build.run(Command::new("adb").args(&["shell", "mkdir", ADB_TEST_DIR])); + build.run(Command::new("adb") + .arg("push") + .arg(build.src.join("src/etc/adb_run_wrapper.sh")) + .arg(ADB_TEST_DIR)); + + let target_dir = format!("{}/{}", ADB_TEST_DIR, target); + build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir[..]])); + + for f in t!(build.sysroot_libdir(compiler, target).read_dir()) { + let f = t!(f); + let name = f.file_name().into_string().unwrap(); + if util::is_dylib(&name) { + build.run(Command::new("adb") + .arg("push") + .arg(f.path()) + .arg(&target_dir)); + } + } } diff --git a/src/bootstrap/build/config.rs b/src/bootstrap/build/config.rs index e155bf356a0..498196e9b6d 100644 --- a/src/bootstrap/build/config.rs +++ b/src/bootstrap/build/config.rs @@ -368,13 +368,13 @@ impl Config { target.ndk = Some(PathBuf::from(value)); } "CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => { - let target = "i686-linux-androideabi".to_string(); + let target = "i686-linux-android".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); target.ndk = Some(PathBuf::from(value)); } "CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => { - let target = "aarch64-linux-androideabi".to_string(); + let target = "aarch64-linux-android".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); target.ndk = Some(PathBuf::from(value)); diff --git a/src/bootstrap/build/dist.rs b/src/bootstrap/build/dist.rs index 088e89b658d..6eed7eaf206 100644 --- a/src/bootstrap/build/dist.rs +++ b/src/bootstrap/build/dist.rs @@ -135,7 +135,6 @@ pub fn rustc(build: &Build, stage: u32, host: &str) { // Prepare the overlay which is part of the tarball but won't actually be // installed - t!(fs::create_dir_all(&overlay)); let cp = |file: &str| { install(&build.src.join(file), &overlay, 0o644); }; @@ -199,7 +198,6 @@ pub fn rustc(build: &Build, stage: u32, host: &str) { // Copy runtime DLLs needed by the compiler if libdir != "bin" { - t!(fs::create_dir_all(image.join(libdir))); for entry in t!(src.join(libdir).read_dir()).map(|e| t!(e)) { let name = entry.file_name(); if let Some(s) = name.to_str() { @@ -221,7 +219,6 @@ pub fn rustc(build: &Build, stage: u32, host: &str) { let cp = |file: &str| { install(&build.src.join(file), &image.join("share/doc/rust"), 0o644); }; - t!(fs::create_dir_all(&image.join("share/doc/rust"))); cp("COPYRIGHT"); cp("LICENSE-APACHE"); cp("LICENSE-MIT"); @@ -289,6 +286,7 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) { fn install(src: &Path, dstdir: &Path, perms: u32) { let dst = dstdir.join(src.file_name().unwrap()); + t!(fs::create_dir_all(dstdir)); t!(fs::copy(src, &dst)); chmod(&dst, perms); } diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index dadb0ffa6c9..195d1bc90c6 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -128,6 +128,7 @@ pub struct Build { /// /// These entries currently correspond to the various output directories of the /// build system, with each mod generating output in a different directory. +#[derive(Clone, Copy)] pub enum Mode { /// This cargo is going to build the standard library, placing output in the /// "stageN-std" directory. @@ -383,8 +384,7 @@ impl Build { "ui", "ui"); } CheckDebuginfo { compiler } => { - if target.target.contains("msvc") || - target.target.contains("android") { + if target.target.contains("msvc") { // nothing to do } else if target.target.contains("apple") { check::compiletest(self, &compiler, target.target, @@ -434,8 +434,14 @@ impl Build { target.target); } + AndroidCopyLibs { compiler } => { + check::android_copy_libs(self, &compiler, target.target); + } + + // pseudo-steps Dist { .. } | - Doc { .. } | // pseudo-steps + Doc { .. } | + CheckTarget { .. } | Check { .. } => {} } } diff --git a/src/bootstrap/build/native.rs b/src/bootstrap/build/native.rs index 557c9a4be54..f6030cfd090 100644 --- a/src/bootstrap/build/native.rs +++ b/src/bootstrap/build/native.rs @@ -49,6 +49,8 @@ pub fn llvm(build: &Build, target: &str) { return } + println!("Building LLVM for {}", target); + let _ = fs::remove_dir_all(&dst.join("build")); t!(fs::create_dir_all(&dst.join("build"))); let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; @@ -167,8 +169,10 @@ pub fn compiler_rt(build: &Build, target: &str) { "arm" if target.contains("eabihf") => "armhf", _ => arch, }; - let target = format!("clang_rt.builtins-{}{}", builtins_arch, os_extra); - ("linux".to_string(), target.clone(), target) + let target = format!("clang_rt.builtins-{}", builtins_arch); + ("linux".to_string(), + target.clone(), + format!("{}{}", target, os_extra)) } else if target.contains("apple-darwin") { let builtins_arch = match arch { "i686" => "i386", diff --git a/src/bootstrap/build/sanity.rs b/src/bootstrap/build/sanity.rs index fd6cdc702cc..5eced00e139 100644 --- a/src/bootstrap/build/sanity.rs +++ b/src/bootstrap/build/sanity.rs @@ -139,6 +139,10 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake "); } } + + if target.contains("arm-linux-android") { + need_cmd("adb".as_ref()); + } } for host in build.flags.host.iter() { diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index 742fd8575bb..7cbbd6740a2 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -102,6 +102,7 @@ macro_rules! targets { // Steps for running tests. The 'check' target is just a pseudo // target to depend on a bunch of others. (check, Check { stage: u32, compiler: Compiler<'a> }), + (check_target, CheckTarget { stage: u32, compiler: Compiler<'a> }), (check_linkcheck, CheckLinkcheck { stage: u32 }), (check_cargotest, CheckCargoTest { stage: u32 }), (check_tidy, CheckTidy { stage: u32 }), @@ -138,6 +139,9 @@ macro_rules! targets { (dist_mingw, DistMingw { _dummy: () }), (dist_rustc, DistRustc { stage: u32 }), (dist_std, DistStd { compiler: Compiler<'a> }), + + // Misc targets + (android_copy_libs, AndroidCopyLibs { compiler: Compiler<'a> }), } } } @@ -382,37 +386,80 @@ impl<'a> Step<'a> { self.doc_error_index(stage)] } Source::Check { stage, compiler } => { - vec![ + // Check is just a pseudo step which means check all targets, + // so just depend on checking all targets. + build.config.target.iter().map(|t| { + self.target(t).check_target(stage, compiler) + }).collect() + } + Source::CheckTarget { stage, compiler } => { + // CheckTarget here means run all possible test suites for this + // target. Most of the time, however, we can't actually run + // anything if we're not the build triple as we could be cross + // compiling. + // + // As a result, the base set of targets here is quite stripped + // down from the standard set of targets. These suites have + // their own internal logic to run in cross-compiled situations + // if they'll run at all. For example compiletest knows that + // when testing Android targets we ship artifacts to the + // emulator. + // + // When in doubt the rule of thumb for adding to this list is + // "should this test suite run on the android bot?" + let mut base = vec![ self.check_rpass(compiler), - self.check_rpass_full(compiler), self.check_rfail(compiler), - self.check_rfail_full(compiler), - self.check_cfail(compiler), - self.check_cfail_full(compiler), - self.check_pfail(compiler), - self.check_incremental(compiler), - self.check_ui(compiler), self.check_crate_std(compiler), self.check_crate_test(compiler), - self.check_crate_rustc(compiler), - self.check_codegen(compiler), - self.check_codegen_units(compiler), self.check_debuginfo(compiler), - self.check_rustdoc(compiler), - self.check_pretty(compiler), - self.check_pretty_rpass(compiler), - self.check_pretty_rpass_full(compiler), - self.check_pretty_rfail(compiler), - self.check_pretty_rfail_full(compiler), - self.check_pretty_rpass_valgrind(compiler), - self.check_rpass_valgrind(compiler), - self.check_error_index(compiler), - self.check_docs(compiler), - self.check_rmake(compiler), - self.check_linkcheck(stage), - self.check_tidy(stage), self.dist(stage), - ] + ]; + + // If we're testing the build triple, then we know we can + // actually run binaries and such, so we run all possible tests + // that we know about. + if self.target == build.config.build { + base.extend(vec![ + // docs-related + self.check_docs(compiler), + self.check_error_index(compiler), + self.check_rustdoc(compiler), + + // UI-related + self.check_cfail(compiler), + self.check_pfail(compiler), + self.check_ui(compiler), + + // codegen-related + self.check_incremental(compiler), + self.check_codegen(compiler), + self.check_codegen_units(compiler), + + // misc compiletest-test suites + self.check_rpass_full(compiler), + self.check_rfail_full(compiler), + self.check_cfail_full(compiler), + self.check_pretty_rpass_full(compiler), + self.check_pretty_rfail_full(compiler), + self.check_rpass_valgrind(compiler), + self.check_rmake(compiler), + + // crates + self.check_crate_rustc(compiler), + + // pretty + self.check_pretty(compiler), + self.check_pretty_rpass(compiler), + self.check_pretty_rfail(compiler), + self.check_pretty_rpass_valgrind(compiler), + + // misc + self.check_linkcheck(stage), + self.check_tidy(stage), + ]); + } + return base } Source::CheckLinkcheck { stage } => { vec![self.tool_linkchecker(stage), self.doc(stage)] @@ -437,16 +484,20 @@ impl<'a> Step<'a> { Source::CheckCFail { compiler } | Source::CheckRPassValgrind { compiler } | Source::CheckRPass { compiler } => { - vec![ + let mut base = vec![ self.libtest(compiler), - self.tool_compiletest(compiler.stage), + self.target(compiler.host).tool_compiletest(compiler.stage), self.test_helpers(()), - ] + ]; + if self.target.contains("android") { + base.push(self.android_copy_libs(compiler)); + } + base } Source::CheckDebuginfo { compiler } => { vec![ self.libtest(compiler), - self.tool_compiletest(compiler.stage), + self.target(compiler.host).tool_compiletest(compiler.stage), self.test_helpers(()), self.debugger_scripts(compiler.stage), ] @@ -459,13 +510,14 @@ impl<'a> Step<'a> { Source::CheckPrettyRPassValgrind { compiler } | Source::CheckRMake { compiler } => { vec![self.librustc(compiler), - self.tool_compiletest(compiler.stage)] + self.target(compiler.host).tool_compiletest(compiler.stage)] } Source::CheckDocs { compiler } => { vec![self.libstd(compiler)] } Source::CheckErrorIndex { compiler } => { - vec![self.libstd(compiler), self.tool_error_index(compiler.stage)] + vec![self.libstd(compiler), + self.target(compiler.host).tool_error_index(compiler.stage)] } Source::CheckCrateStd { compiler } => { vec![self.libtest(compiler)] @@ -529,6 +581,10 @@ impl<'a> Step<'a> { } return base } + + Source::AndroidCopyLibs { compiler } => { + vec![self.libtest(compiler)] + } } } } diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 1f3ea8f19bb..c657785d78b 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -25,6 +25,11 @@ all: clean: $(Q)$(BOOTSTRAP) --clean +rustc-stage1: + $(Q)$(BOOTSTRAP) --step libtest --stage 1 +rustc-stage2: + $(Q)$(BOOTSTRAP) --step libtest --stage 2 + docs: doc doc: $(Q)$(BOOTSTRAP) --step doc diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index edb965c1962..94baf188bca 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -293,6 +293,12 @@ extern "rust-intrinsic" { #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute<T, U>(e: T) -> U; + /// Gives the address for the return value of the enclosing function. + /// + /// Using this intrinsic in a function that does not use an out pointer + /// will trigger a compiler error. + pub fn return_address() -> *const u8; + /// Returns `true` if the actual type given as `T` requires drop /// glue; returns `false` if the actual type provided for `T` /// implements `Copy`. diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index 70d0a4e315c..4e16fae1870 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -118,8 +118,6 @@ impl DepGraphThreadData { /// the buffer is full, this may swap.) #[inline] pub fn enqueue(&self, message: DepMessage) { - debug!("enqueue: {:?} tasks_pushed={}", message, self.tasks_pushed.get()); - // Regardless of whether dep graph construction is enabled, we // still want to check that we always have a valid task on the // stack when a read/write/etc event occurs. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b6591471f0e..3b9ecb88258 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -908,6 +908,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.note("only the last field of a struct or enum variant \ may have a dynamically sized type"); } + ObligationCauseCode::ConstSized => { + err.note("constant expressions must have a statically known size"); + } ObligationCauseCode::SharedStatic => { err.note("shared static variables must have a type that implements `Sync`"); } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 68db5f86476..17aa6544fe7 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -127,6 +127,9 @@ pub enum ObligationCauseCode<'tcx> { // Types of fields (other than the last) in a struct must be sized. FieldSized, + // Constant expressions must be sized. + ConstSized, + // static items must have `Sync` type SharedStatic, diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index b3918f1e4bc..91234631499 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -15,6 +15,7 @@ use std::marker::PhantomData; use std::ops::{Index, IndexMut, Range}; use std::fmt; use std::vec; +use std::u32; use rustc_serialize as serialize; @@ -31,6 +32,11 @@ impl Idx for usize { fn index(self) -> usize { self } } +impl Idx for u32 { + fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 } + fn index(self) -> usize { self as usize } +} + #[derive(Clone)] pub struct IndexVec<I: Idx, T> { pub raw: Vec<T>, diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index b713b2285a6..c079146edbf 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -208,11 +208,17 @@ impl<O: ForestObligation> ObligationForest<O> { /// /// This CAN be done in a snapshot pub fn register_obligation(&mut self, obligation: O) { - self.register_obligation_at(obligation, None) + // Ignore errors here - there is no guarantee of success. + let _ = self.register_obligation_at(obligation, None); } - fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>) { - if self.done_cache.contains(obligation.as_predicate()) { return } + // returns Err(()) if we already know this obligation failed. + fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>) + -> Result<(), ()> + { + if self.done_cache.contains(obligation.as_predicate()) { + return Ok(()) + } match self.waiting_cache.entry(obligation.as_predicate().clone()) { Entry::Occupied(o) => { @@ -226,6 +232,11 @@ impl<O: ForestObligation> ObligationForest<O> { self.nodes[o.get().get()].dependents.push(parent); } } + if let NodeState::Error = self.nodes[o.get().get()].state.get() { + Err(()) + } else { + Ok(()) + } } Entry::Vacant(v) => { debug!("register_obligation_at({:?}, {:?}) - ok", @@ -233,8 +244,9 @@ impl<O: ForestObligation> ObligationForest<O> { v.insert(NodeIndex::new(self.nodes.len())); self.cache_list.push(obligation.as_predicate().clone()); self.nodes.push(Node::new(parent, obligation)); + Ok(()) } - }; + } } /// Convert all remaining obligations to the given error. @@ -306,12 +318,19 @@ impl<O: ForestObligation> ObligationForest<O> { Ok(Some(children)) => { // if we saw a Some(_) result, we are not (yet) stalled stalled = false; + self.nodes[index].state.set(NodeState::Success); + for child in children { - self.register_obligation_at(child, - Some(NodeIndex::new(index))); + let st = self.register_obligation_at( + child, + Some(NodeIndex::new(index)) + ); + if let Err(()) = st { + // error already reported - propagate it + // to our node. + self.error_at(index); + } } - - self.nodes[index].state.set(NodeState::Success); } Err(err) => { let backtrace = self.error_at(index); diff --git a/src/librustc_data_structures/obligation_forest/test.rs b/src/librustc_data_structures/obligation_forest/test.rs index 8eac8892a3e..a95b2b84b34 100644 --- a/src/librustc_data_structures/obligation_forest/test.rs +++ b/src/librustc_data_structures/obligation_forest/test.rs @@ -418,3 +418,43 @@ fn orphan() { let errors = forest.to_errors(()); assert_eq!(errors.len(), 0); } + +#[test] +fn simultaneous_register_and_error() { + // check that registering a failed obligation works correctly + let mut forest = ObligationForest::new(); + forest.register_obligation("A"); + forest.register_obligation("B"); + + let Outcome { completed: ok, errors: err, .. } = + forest.process_obligations(&mut C(|obligation| { + match *obligation { + "A" => Err("An error"), + "B" => Ok(Some(vec!["A"])), + _ => unreachable!(), + } + }, |_|{})); + assert_eq!(ok.len(), 0); + assert_eq!(err, vec![super::Error { + error: "An error", + backtrace: vec!["A"] + }]); + + let mut forest = ObligationForest::new(); + forest.register_obligation("B"); + forest.register_obligation("A"); + + let Outcome { completed: ok, errors: err, .. } = + forest.process_obligations(&mut C(|obligation| { + match *obligation { + "A" => Err("An error"), + "B" => Ok(Some(vec!["A"])), + _ => unreachable!(), + } + }, |_|{})); + assert_eq!(ok.len(), 0); + assert_eq!(err, vec![super::Error { + error: "An error", + backtrace: vec!["A"] + }]); +} diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 11896e17630..2d3302c2eef 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -16,6 +16,7 @@ rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } serialize = { path = "../libserialize" } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 7ef00b971c5..2e8c5a7c234 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -60,7 +60,7 @@ use rustc_serialize::{Encodable, EncoderHelpers}; struct DecodeContext<'a, 'b, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &'b cstore::crate_metadata, + cdata: &'b cstore::CrateMetadata, from_id_range: IdRange, to_id_range: IdRange, // Cache the last used filemap for translating spans as an optimization. @@ -121,7 +121,7 @@ impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> { /// Decodes an item from its AST in the cdata's metadata and adds it to the /// ast-map. -pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::crate_metadata, +pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, tcx: TyCtxt<'a, 'tcx, 'tcx>, parent_def_path: ast_map::DefPath, parent_did: DefId, @@ -246,7 +246,7 @@ impl<S:serialize::Encoder> def_id_encoder_helpers for S trait def_id_decoder_helpers { fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId; fn read_def_id_nodcx(&mut self, - cdata: &cstore::crate_metadata) -> DefId; + cdata: &cstore::CrateMetadata) -> DefId; } impl<D:serialize::Decoder> def_id_decoder_helpers for D @@ -258,7 +258,7 @@ impl<D:serialize::Decoder> def_id_decoder_helpers for D } fn read_def_id_nodcx(&mut self, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> DefId { let did: DefId = Decodable::decode(self).unwrap(); decoder::translate_def_id(cdata, did) @@ -858,17 +858,17 @@ trait rbml_decoder_decoder_helpers<'tcx> { // Versions of the type reading functions that don't need the full // DecodeContext. fn read_ty_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) -> Ty<'tcx>; + cdata: &cstore::CrateMetadata) -> Ty<'tcx>; fn read_tys_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) -> Vec<Ty<'tcx>>; + cdata: &cstore::CrateMetadata) -> Vec<Ty<'tcx>>; fn read_substs_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> subst::Substs<'tcx>; } impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_ty_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> Ty<'tcx> { self.read_opaque(|_, doc| { Ok( @@ -879,7 +879,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_tys_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) -> Vec<Ty<'tcx>> { + cdata: &cstore::CrateMetadata) -> Vec<Ty<'tcx>> { self.read_to_vec(|this| Ok(this.read_ty_nodcx(tcx, cdata)) ) .unwrap() .into_iter() @@ -887,7 +887,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_substs_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> subst::Substs<'tcx> { self.read_opaque(|_, doc| { diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 74f97de2658..ff072cce5db 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -252,3 +252,7 @@ pub fn rustc_version() -> String { } pub const tag_panic_strategy: usize = 0x114; + +// NB: increment this if you change the format of metadata such that +// rustc_version can't be found. +pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2ccac91ae91..269e284b22d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -12,7 +12,6 @@ //! Validates all used crates and extern libraries and loads their metadata -use common::rustc_version; use cstore::{self, CStore, CrateSource, MetadataBlob}; use decoder; use loader::{self, CratePaths}; @@ -24,7 +23,7 @@ use rustc::session::{config, Session}; use rustc::session::config::PanicStrategy; use rustc::session::search_paths::PathKind; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use rustc::hir::map as hir_map; use std::cell::{RefCell, Cell}; @@ -132,7 +131,7 @@ struct ExtensionCrate { } enum PMDSource { - Registered(Rc<cstore::crate_metadata>), + Registered(Rc<cstore::CrateMetadata>), Owned(MetadataBlob), } @@ -236,25 +235,6 @@ impl<'a> CrateReader<'a> { return ret; } - fn verify_rustc_version(&self, - name: &str, - span: Span, - metadata: &MetadataBlob) { - let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice()); - if crate_rustc_version != Some(rustc_version()) { - let mut err = struct_span_fatal!(self.sess, span, E0514, - "the crate `{}` has been compiled with {}, which is \ - incompatible with this version of rustc", - name, - crate_rustc_version - .as_ref().map(|s| &**s) - .unwrap_or("an old version of rustc")); - err.help("consider removing the compiled binaries and recompiling \ - with your current version of rustc"); - err.emit(); - } - } - fn verify_no_symbol_conflicts(&self, span: Span, metadata: &MetadataBlob) { @@ -294,9 +274,8 @@ impl<'a> CrateReader<'a> { span: Span, lib: loader::Library, explicitly_linked: bool) - -> (ast::CrateNum, Rc<cstore::crate_metadata>, + -> (ast::CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) { - self.verify_rustc_version(name, span, &lib.metadata); self.verify_no_symbol_conflicts(span, &lib.metadata); // Claim this crate number and cache it @@ -318,10 +297,10 @@ impl<'a> CrateReader<'a> { let loader::Library { dylib, rlib, metadata } = lib; - let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span); + let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), cnum, span); let staged_api = self.is_staged_api(metadata.as_slice()); - let cmeta = Rc::new(cstore::crate_metadata { + let cmeta = Rc::new(cstore::CrateMetadata { name: name.to_string(), extern_crate: Cell::new(None), index: decoder::load_index(metadata.as_slice()), @@ -364,7 +343,7 @@ impl<'a> CrateReader<'a> { span: Span, kind: PathKind, explicitly_linked: bool) - -> (ast::CrateNum, Rc<cstore::crate_metadata>, cstore::CrateSource) { + -> (ast::CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) { let result = match self.existing_match(name, hash, kind) { Some(cnum) => LoadResult::Previous(cnum), None => { @@ -381,6 +360,7 @@ impl<'a> CrateReader<'a> { rejected_via_hash: vec!(), rejected_via_triple: vec!(), rejected_via_kind: vec!(), + rejected_via_version: vec!(), should_match_name: true, }; match self.load(&mut load_ctxt) { @@ -438,8 +418,11 @@ impl<'a> CrateReader<'a> { fn update_extern_crate(&mut self, cnum: ast::CrateNum, - mut extern_crate: ExternCrate) + mut extern_crate: ExternCrate, + visited: &mut FnvHashSet<(ast::CrateNum, bool)>) { + if !visited.insert((cnum, extern_crate.direct)) { return } + let cmeta = self.cstore.get_crate_data(cnum); let old_extern_crate = cmeta.extern_crate.get(); @@ -458,11 +441,10 @@ impl<'a> CrateReader<'a> { } cmeta.extern_crate.set(Some(extern_crate)); - // Propagate the extern crate info to dependencies. extern_crate.direct = false; - for &dep_cnum in cmeta.cnum_map.borrow().values() { - self.update_extern_crate(dep_cnum, extern_crate); + for &dep_cnum in cmeta.cnum_map.borrow().iter() { + self.update_extern_crate(dep_cnum, extern_crate, visited); } } @@ -470,12 +452,13 @@ impl<'a> CrateReader<'a> { fn resolve_crate_deps(&mut self, root: &Option<CratePaths>, cdata: &[u8], - span : Span) - -> cstore::cnum_map { + krate: ast::CrateNum, + span: Span) + -> cstore::CrateNumMap { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers - decoder::get_crate_deps(cdata).iter().map(|dep| { + let map: FnvHashMap<_, _> = decoder::get_crate_deps(cdata).iter().map(|dep| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); let (local_cnum, _, _) = self.resolve_crate(root, &dep.name, @@ -485,7 +468,13 @@ impl<'a> CrateReader<'a> { PathKind::Dependency, dep.explicitly_linked); (dep.cnum, local_cnum) - }).collect() + }).collect(); + + let max_cnum = map.values().cloned().max().unwrap_or(0); + + // we map 0 and all other holes in the map to our parent crate. The "additional" + // self-dependencies should be harmless. + (0..max_cnum+1).map(|cnum| map.get(&cnum).cloned().unwrap_or(krate)).collect() } fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { @@ -508,6 +497,7 @@ impl<'a> CrateReader<'a> { rejected_via_hash: vec!(), rejected_via_triple: vec!(), rejected_via_kind: vec!(), + rejected_via_version: vec!(), should_match_name: true, }; let library = self.load(&mut load_ctxt).or_else(|| { @@ -826,7 +816,7 @@ impl<'a> CrateReader<'a> { fn inject_dependency_if(&self, krate: ast::CrateNum, what: &str, - needs_dep: &Fn(&cstore::crate_metadata) -> bool) { + needs_dep: &Fn(&cstore::CrateMetadata) -> bool) { // don't perform this validation if the session has errors, as one of // those errors may indicate a circular dependency which could cause // this to stack overflow. @@ -837,7 +827,17 @@ impl<'a> CrateReader<'a> { // Before we inject any dependencies, make sure we don't inject a // circular dependency by validating that this crate doesn't // transitively depend on any crates satisfying `needs_dep`. - validate(self, krate, krate, what, needs_dep); + for dep in self.cstore.crate_dependencies_in_rpo(krate) { + let data = self.cstore.get_crate_data(dep); + if needs_dep(&data) { + self.sess.err(&format!("the crate `{}` cannot depend \ + on a crate that needs {}, but \ + it depends on `{}`", + self.cstore.get_crate_data(krate).name(), + what, + data.name())); + } + } // All crates satisfying `needs_dep` do not explicitly depend on the // crate provided for this compile, but in order for this compilation to @@ -849,32 +849,8 @@ impl<'a> CrateReader<'a> { } info!("injecting a dep from {} to {}", cnum, krate); - let mut cnum_map = data.cnum_map.borrow_mut(); - let remote_cnum = cnum_map.len() + 1; - let prev = cnum_map.insert(remote_cnum as ast::CrateNum, krate); - assert!(prev.is_none()); + data.cnum_map.borrow_mut().push(krate); }); - - fn validate(me: &CrateReader, - krate: ast::CrateNum, - root: ast::CrateNum, - what: &str, - needs_dep: &Fn(&cstore::crate_metadata) -> bool) { - let data = me.cstore.get_crate_data(krate); - if needs_dep(&data) { - let krate_name = data.name(); - let data = me.cstore.get_crate_data(root); - let root_name = data.name(); - me.sess.err(&format!("the crate `{}` cannot depend \ - on a crate that needs {}, but \ - it depends on `{}`", root_name, what, - krate_name)); - } - - for (_, &dep) in data.cnum_map.borrow().iter() { - validate(me, dep, root, what, needs_dep); - } - } } } @@ -948,7 +924,8 @@ impl<'a> LocalCrateReader<'a> { span: i.span, direct: true, path_len: len, - }); + }, + &mut FnvHashSet()); self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 3134a3844bc..95e3c53ecb4 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -9,6 +9,7 @@ // except according to those terms. use cstore; +use common; use decoder; use encoder; use loader; @@ -588,7 +589,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn metadata_encoding_version(&self) -> &[u8] { - encoder::metadata_encoding_version + common::metadata_encoding_version } /// Returns a map from a sufficiently visible external item (i.e. an external item that is diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index e89f428c96f..774d0f7ea18 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -15,6 +15,7 @@ pub use self::MetadataBlob::*; +use common; use creader; use decoder; use index; @@ -26,6 +27,7 @@ use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::{ExternCrate}; use rustc::session::config::PanicStrategy; +use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; use std::cell::{RefCell, Ref, Cell}; @@ -46,7 +48,7 @@ pub use middle::cstore::{CrateSource, LinkMeta}; // local crate numbers (as generated during this session). Each external // crate may refer to types in other external crates, and each has their // own crate numbers. -pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>; +pub type CrateNumMap = IndexVec<ast::CrateNum, ast::CrateNum>; pub enum MetadataBlob { MetadataVec(Bytes), @@ -64,7 +66,7 @@ pub struct ImportedFileMap { pub translated_filemap: Rc<syntax_pos::FileMap> } -pub struct crate_metadata { +pub struct CrateMetadata { pub name: String, /// Information about the extern crate that caused this crate to @@ -73,7 +75,7 @@ pub struct crate_metadata { pub extern_crate: Cell<Option<ExternCrate>>, pub data: MetadataBlob, - pub cnum_map: RefCell<cnum_map>, + pub cnum_map: RefCell<CrateNumMap>, pub cnum: ast::CrateNum, pub codemap_import_info: RefCell<Vec<ImportedFileMap>>, pub staged_api: bool, @@ -97,7 +99,7 @@ pub struct crate_metadata { pub struct CStore { pub dep_graph: DepGraph, - metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>, + metas: RefCell<FnvHashMap<ast::CrateNum, Rc<CrateMetadata>>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>, used_crate_sources: RefCell<Vec<CrateSource>>, @@ -128,7 +130,7 @@ impl CStore { self.metas.borrow().len() as ast::CrateNum + 1 } - pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> { + pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<CrateMetadata> { self.metas.borrow().get(&cnum).unwrap().clone() } @@ -137,12 +139,12 @@ impl CStore { decoder::get_crate_hash(cdata.data()) } - pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) { + pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<CrateMetadata>) { self.metas.borrow_mut().insert(cnum, data); } pub fn iter_crate_data<I>(&self, mut i: I) where - I: FnMut(ast::CrateNum, &Rc<crate_metadata>), + I: FnMut(ast::CrateNum, &Rc<CrateMetadata>), { for (&k, v) in self.metas.borrow().iter() { i(k, v); @@ -151,7 +153,7 @@ impl CStore { /// Like `iter_crate_data`, but passes source paths (if available) as well. pub fn iter_crate_data_origins<I>(&self, mut i: I) where - I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>), + I: FnMut(ast::CrateNum, &CrateMetadata, Option<CrateSource>), { for (&k, v) in self.metas.borrow().iter() { let origin = self.opt_used_crate_source(k); @@ -182,6 +184,30 @@ impl CStore { self.statically_included_foreign_items.borrow_mut().clear(); } + pub fn crate_dependencies_in_rpo(&self, krate: ast::CrateNum) -> Vec<ast::CrateNum> + { + let mut ordering = Vec::new(); + self.push_dependencies_in_postorder(&mut ordering, krate); + ordering.reverse(); + ordering + } + + pub fn push_dependencies_in_postorder(&self, + ordering: &mut Vec<ast::CrateNum>, + krate: ast::CrateNum) + { + if ordering.contains(&krate) { return } + + let data = self.get_crate_data(krate); + for &dep in data.cnum_map.borrow().iter() { + if dep != krate { + self.push_dependencies_in_postorder(ordering, dep); + } + } + + ordering.push(krate); + } + // This method is used when generating the command line to pass through to // system linker. The linker expects undefined symbols on the left of the // command line to be defined in libraries on the right, not the other way @@ -194,17 +220,8 @@ impl CStore { pub fn do_get_used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)> { let mut ordering = Vec::new(); - fn visit(cstore: &CStore, cnum: ast::CrateNum, - ordering: &mut Vec<ast::CrateNum>) { - if ordering.contains(&cnum) { return } - let meta = cstore.get_crate_data(cnum); - for (_, &dep) in meta.cnum_map.borrow().iter() { - visit(cstore, dep, ordering); - } - ordering.push(cnum); - } for (&num, _) in self.metas.borrow().iter() { - visit(self, num, &mut ordering); + self.push_dependencies_in_postorder(&mut ordering, num); } info!("topological ordering: {:?}", ordering); ordering.reverse(); @@ -264,7 +281,7 @@ impl CStore { } } -impl crate_metadata { +impl CrateMetadata { pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) } pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } @@ -312,20 +329,25 @@ impl crate_metadata { } impl MetadataBlob { - pub fn as_slice<'a>(&'a self) -> &'a [u8] { - let slice = match *self { + pub fn as_slice_raw<'a>(&'a self) -> &'a [u8] { + match *self { MetadataVec(ref vec) => &vec[..], MetadataArchive(ref ar) => ar.as_slice(), - }; - if slice.len() < 4 { + } + } + + pub fn as_slice<'a>(&'a self) -> &'a [u8] { + let slice = self.as_slice_raw(); + let len_offset = 4 + common::metadata_encoding_version.len(); + if slice.len() < len_offset+4 { &[] // corrupt metadata } else { - let len = (((slice[0] as u32) << 24) | - ((slice[1] as u32) << 16) | - ((slice[2] as u32) << 8) | - ((slice[3] as u32) << 0)) as usize; - if len + 4 <= slice.len() { - &slice[4.. len + 4] + let len = (((slice[len_offset+0] as u32) << 24) | + ((slice[len_offset+1] as u32) << 16) | + ((slice[len_offset+2] as u32) << 8) | + ((slice[len_offset+3] as u32) << 0)) as usize; + if len <= slice.len() - 4 - len_offset { + &slice[len_offset + 4..len_offset + len + 4] } else { &[] // corrupt or old metadata } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3efdf36acd9..0a59c152ca3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -15,7 +15,7 @@ use self::Family::*; use astencode::decode_inlined_item; -use cstore::{self, crate_metadata}; +use cstore::{self, CrateMetadata}; use common::*; use def_key; use encoder::def_to_u64; @@ -30,7 +30,7 @@ use rustc::util::nodemap::FnvHashMap; use rustc::hir; use rustc::session::config::PanicStrategy; -use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference}; +use middle::cstore::{FoundAst, InlinedItem, LinkagePreference}; use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; @@ -61,9 +61,9 @@ use syntax::print::pprust; use syntax::ptr::P; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; -pub type Cmd<'a> = &'a crate_metadata; +pub type Cmd<'a> = &'a CrateMetadata; -impl crate_metadata { +impl CrateMetadata { fn get_item(&self, item_id: DefIndex) -> Option<rbml::Doc> { self.index.lookup_item(self.data(), item_id).map(|pos| { reader::doc_at(self.data(), pos as usize).unwrap().doc @@ -663,7 +663,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>, mut get_crate_data: G, mut callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc<crate_metadata>, + G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>, { // Iterate over all children. for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) { @@ -758,7 +758,7 @@ pub fn each_child_of_item<F, G>(intr: Rc<IdentInterner>, get_crate_data: G, callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc<crate_metadata>, + G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>, { // Find the item. let item_doc = match cdata.get_item(id) { @@ -779,7 +779,7 @@ pub fn each_top_level_item_of_crate<F, G>(intr: Rc<IdentInterner>, get_crate_data: G, callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc<crate_metadata>, + G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>, { let root_doc = rbml::Doc::new(cdata.data()); let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); @@ -1348,25 +1348,16 @@ pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId { return DefId { krate: cdata.cnum, index: did.index }; } - match cdata.cnum_map.borrow().get(&did.krate) { - Some(&n) => { - DefId { - krate: n, - index: did.index, - } - } - None => bug!("didn't find a crate in the cnum_map") + DefId { + krate: cdata.cnum_map.borrow()[did.krate], + index: did.index } } // Translate a DefId from the current compilation environment to a DefId // for an external crate. fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> { - if did.krate == cdata.cnum { - return Some(DefId { krate: LOCAL_CRATE, index: did.index }); - } - - for (&local, &global) in cdata.cnum_map.borrow().iter() { + for (local, &global) in cdata.cnum_map.borrow().iter_enumerated() { if global == did.krate { return Some(DefId { krate: local, index: did.index }); } @@ -1545,10 +1536,7 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) let cnum = spec.split(':').nth(0).unwrap(); let link = spec.split(':').nth(1).unwrap(); let cnum: ast::CrateNum = cnum.parse().unwrap(); - let cnum = match cdata.cnum_map.borrow().get(&cnum) { - Some(&n) => n, - None => bug!("didn't find a crate in the cnum_map") - }; + let cnum = cdata.cnum_map.borrow()[cnum]; result.push((cnum, if link == "d" { LinkagePreference::RequireDynamic } else { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index c23ad6d5f07..b6f49569958 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1351,6 +1351,7 @@ fn my_visit_expr(expr: &hir::Expr, rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); + encode_name(rbml_w, syntax::parse::token::intern("<closure>")); rbml_w.start_tag(tag_items_closure_ty); write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); @@ -1505,7 +1506,7 @@ fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) { fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { fn get_ordered_deps(cstore: &cstore::CStore) - -> Vec<(CrateNum, Rc<cstore::crate_metadata>)> { + -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> { // Pull the cnums and name,vers,hash out of cstore let mut deps = Vec::new(); cstore.iter_crate_data(|cnum, val| { @@ -1736,7 +1737,7 @@ fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) { } fn encode_crate_dep(rbml_w: &mut Encoder, - dep: &cstore::crate_metadata) { + dep: &cstore::CrateMetadata) { rbml_w.start_tag(tag_crate_dep); rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); let hash = decoder::get_crate_hash(dep.data()); @@ -1798,10 +1799,6 @@ fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) { } } -// NB: Increment this as you change the metadata encoding version. -#[allow(non_upper_case_globals)] -pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ]; - pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec<u8> { let mut wr = Cursor::new(Vec::new()); @@ -1835,12 +1832,25 @@ pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec<u8> { // the length of the metadata to the start of the metadata. Later on this // will allow us to slice the metadata to the precise length that we just // generated regardless of trailing bytes that end up in it. - let len = v.len() as u32; - v.insert(0, (len >> 0) as u8); - v.insert(0, (len >> 8) as u8); - v.insert(0, (len >> 16) as u8); - v.insert(0, (len >> 24) as u8); - return v; + // + // We also need to store the metadata encoding version here, because + // rlibs don't have it. To get older versions of rustc to ignore + // this metadata, there are 4 zero bytes at the start, which are + // treated as a length of 0 by old compilers. + + let len = v.len(); + let mut result = vec![]; + result.push(0); + result.push(0); + result.push(0); + result.push(0); + result.extend(metadata_encoding_version.iter().cloned()); + result.push((len >> 24) as u8); + result.push((len >> 16) as u8); + result.push((len >> 8) as u8); + result.push((len >> 0) as u8); + result.extend(v); + result } fn encode_metadata_inner(rbml_w: &mut Encoder, diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 1cf7282e9e9..cd92493e3db 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -36,6 +36,7 @@ extern crate rustc_errors as errors; #[macro_use] extern crate rustc; +extern crate rustc_data_structures; extern crate rustc_back; extern crate rustc_llvm; extern crate rustc_const_math; diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 56393b79980..edfdbf2aeef 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -213,8 +213,8 @@ //! metadata::loader or metadata::creader for all the juicy details! use cstore::{MetadataBlob, MetadataVec, MetadataArchive}; +use common::{metadata_encoding_version, rustc_version}; use decoder; -use encoder; use rustc::hir::svh::Svh; use rustc::session::Session; @@ -260,6 +260,7 @@ pub struct Context<'a> { pub rejected_via_hash: Vec<CrateMismatch>, pub rejected_via_triple: Vec<CrateMismatch>, pub rejected_via_kind: Vec<CrateMismatch>, + pub rejected_via_version: Vec<CrateMismatch>, pub should_match_name: bool, } @@ -336,6 +337,10 @@ impl<'a> Context<'a> { struct_span_err!(self.sess, self.span, E0462, "found staticlib `{}` instead of rlib or dylib{}", self.ident, add) + } else if !self.rejected_via_version.is_empty() { + struct_span_err!(self.sess, self.span, E0514, + "found crate `{}` compiled by an incompatible version of rustc{}", + self.ident, add) } else { struct_span_err!(self.sess, self.span, E0463, "can't find crate for `{}`{}", @@ -350,7 +355,7 @@ impl<'a> Context<'a> { } } if !self.rejected_via_hash.is_empty() { - err.note("perhaps this crate needs to be recompiled?"); + err.note("perhaps that crate needs to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { err.note(&format!("crate `{}` path #{}: {}", @@ -367,13 +372,22 @@ impl<'a> Context<'a> { } } if !self.rejected_via_kind.is_empty() { - err.help("please recompile this crate using --crate-type lib"); + err.help("please recompile that crate using --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { err.note(&format!("crate `{}` path #{}: {}", self.ident, i+1, path.display())); } } + if !self.rejected_via_version.is_empty() { + err.help(&format!("please recompile that crate using this compiler ({})", + rustc_version())); + let mismatches = self.rejected_via_version.iter(); + for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() { + err.note(&format!("crate `{}` path #{}: {} compiled by {:?}", + self.ident, i+1, path.display(), got)); + } + } err.emit(); self.sess.abort_if_errors(); @@ -591,6 +605,17 @@ impl<'a> Context<'a> { } fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> Option<Svh> { + let crate_rustc_version = decoder::crate_rustc_version(crate_data); + if crate_rustc_version != Some(rustc_version()) { + let message = crate_rustc_version.unwrap_or(format!("an unknown compiler")); + info!("Rejecting via version: expected {} got {}", rustc_version(), message); + self.rejected_via_version.push(CrateMismatch { + path: libpath.to_path_buf(), + got: message + }); + return None; + } + if self.should_match_name { match decoder::maybe_get_crate_name(crate_data) { Some(ref name) if self.crate_name == *name => {} @@ -742,6 +767,21 @@ impl ArchiveMetadata { pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } } } +fn verify_decompressed_encoding_version(blob: &MetadataBlob, filename: &Path) + -> Result<(), String> +{ + let data = blob.as_slice_raw(); + if data.len() < 4+metadata_encoding_version.len() || + !<[u8]>::eq(&data[..4], &[0, 0, 0, 0]) || + &data[4..4+metadata_encoding_version.len()] != metadata_encoding_version + { + Err((format!("incompatible metadata version found: '{}'", + filename.display()))) + } else { + Ok(()) + } +} + // Just a small wrapper to time how long reading metadata takes. fn get_metadata_section(target: &Target, flavor: CrateFlavor, filename: &Path) -> Result<MetadataBlob, String> { @@ -772,7 +812,10 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) { None => Err(format!("failed to read rlib metadata: '{}'", filename.display())), - Some(blob) => Ok(blob) + Some(blob) => { + try!(verify_decompressed_encoding_version(&blob, filename)); + Ok(blob) + } }; } unsafe { @@ -801,12 +844,12 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat let cbuf = llvm::LLVMGetSectionContents(si.llsi); let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; let cvbuf: *const u8 = cbuf as *const u8; - let vlen = encoder::metadata_encoding_version.len(); + let vlen = metadata_encoding_version.len(); debug!("checking {} bytes of metadata-version stamp", vlen); let minsz = cmp::min(vlen, csz); let buf0 = slice::from_raw_parts(cvbuf, minsz); - let version_ok = buf0 == encoder::metadata_encoding_version; + let version_ok = buf0 == metadata_encoding_version; if !version_ok { return Err((format!("incompatible metadata version found: '{}'", filename.display()))); @@ -817,7 +860,11 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat csz - vlen); let bytes = slice::from_raw_parts(cvbuf1, csz - vlen); match flate::inflate_bytes(bytes) { - Ok(inflated) => return Ok(MetadataVec(inflated)), + Ok(inflated) => { + let blob = MetadataVec(inflated); + try!(verify_decompressed_encoding_version(&blob, filename)); + return Ok(blob); + } Err(_) => {} } } diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs index f7f065a3562..d36878b0332 100644 --- a/src/librustc_trans/diagnostics.rs +++ b/src/librustc_trans/diagnostics.rs @@ -12,6 +12,44 @@ register_long_diagnostics! { +E0510: r##" +`return_address` was used in an invalid context. Erroneous code example: + +```ignore +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +unsafe fn by_value() -> i32 { + let _ = return_address(); + // error: invalid use of `return_address` intrinsic: function does + // not use out pointer + 0 +} +``` + +Return values may be stored in a return register(s) or written into a so-called +out pointer. In case the returned value is too big (this is +target-ABI-dependent and generally not portable or future proof) to fit into +the return register(s), the compiler will return the value by writing it into +space allocated in the caller's stack frame. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +unsafe fn by_pointer() -> String { + let _ = return_address(); + String::new() // ok! +} +``` +"##, + E0511: r##" Invalid monomorphization of an intrinsic function was used. Erroneous code example: diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index a721361fce0..bd24647edf0 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -617,6 +617,18 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }, + + (_, "return_address") => { + if !fcx.fn_ty.ret.is_indirect() { + span_err!(tcx.sess, span, E0510, + "invalid use of `return_address` intrinsic: function \ + does not use out pointer"); + C_null(Type::i8p(ccx)) + } else { + PointerCast(bcx, llvm::get_param(fcx.llfn, 0), Type::i8p(ccx)) + } + } + (_, "discriminant_value") => { let val_ty = substs.types.get(FnSpace, 0); match val_ty.sty { diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index fa00ea1e780..ab859b88a85 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -169,8 +169,7 @@ pub struct Instance<'tcx> { impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[], - |tcx| Some(tcx.lookup_item_type(self.def).generics)) + ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[], |_| None) } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 5a3268e9e44..0fb08ec9855 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -275,6 +275,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), + "return_address" => (0, vec![], tcx.mk_imm_ptr(tcx.types.u8)), + "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()), "discriminant_value" => (1, vec![ diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 83b5ab71cc2..3bc90f05d25 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1157,6 +1157,7 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let rty = ccx.tcx.node_id_to_type(id); let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), e.id); let declty = fcx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty; + fcx.require_type_is_sized(declty, e.span, traits::ConstSized); fcx.check_const_with_ty(sp, e, declty); }); } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index c103ff7f4b0..462e50a72cc 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1057,7 +1057,6 @@ impl PathBuf { self._push(path.as_ref()) } - #[allow(deprecated)] fn _push(&mut self, path: &Path) { // in general, a separator is needed if the rightmost byte is not a separator let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 3c88fb8f670..e01bd2a93aa 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -34,6 +34,27 @@ thread_local! { static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new()) } +enum AttrError { + MultipleItem(InternedString), + UnknownMetaItem(InternedString), + MissingSince, + MissingFeature, + MultipleStabilityLevels, +} + +fn handle_errors(diag: &Handler, span: Span, error: AttrError) { + match error { + AttrError::MultipleItem(item) => span_err!(diag, span, E0538, + "multiple '{}' items", item), + AttrError::UnknownMetaItem(item) => span_err!(diag, span, E0541, + "unknown meta item '{}'", item), + AttrError::MissingSince => span_err!(diag, span, E0542, "missing 'since'"), + AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"), + AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544, + "multiple stability levels"), + } +} + pub fn mark_used(attr: &Attribute) { let AttrId(id) = attr.node.id; USED_ATTRS.with(|slot| { @@ -303,10 +324,10 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option<Inte if let s@Some(_) = attr.value_str() { s } else { - diag.struct_span_err(attr.span, - "export_name attribute has invalid format") - .help("use #[export_name=\"*\"]") - .emit(); + struct_span_err!(diag, attr.span, E0533, + "export_name attribute has invalid format") + .help("use #[export_name=\"*\"]") + .emit(); None } } else { @@ -339,14 +360,16 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In MetaItemKind::List(ref n, ref items) if n == "inline" => { mark_used(attr); if items.len() != 1 { - diagnostic.map(|d|{ d.span_err(attr.span, "expected one argument"); }); + diagnostic.map(|d|{ span_err!(d, attr.span, E0534, "expected one argument"); }); InlineAttr::None } else if contains_name(&items[..], "always") { InlineAttr::Always } else if contains_name(&items[..], "never") { InlineAttr::Never } else { - diagnostic.map(|d|{ d.span_err((*items[0]).span, "invalid argument"); }); + diagnostic.map(|d| { + span_err!(d, (*items[0]).span, E0535, "invalid argument"); + }); InlineAttr::None } } @@ -374,13 +397,13 @@ pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem, mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)), ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => { if mis.len() != 1 { - sess.span_diagnostic.span_err(cfg.span, "expected 1 cfg-pattern"); + span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); return false; } !cfg_matches(cfgs, &mis[0], sess, features) } ast::MetaItemKind::List(ref pred, _) => { - sess.span_diagnostic.span_err(cfg.span, &format!("invalid predicate `{}`", pred)); + span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", pred); false }, ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => { @@ -446,15 +469,14 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, if let Some(metas) = attr.meta_item_list() { let get = |meta: &MetaItem, item: &mut Option<InternedString>| { if item.is_some() { - diagnostic.span_err(meta.span, &format!("multiple '{}' items", - meta.name())); + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); return false } if let Some(v) = meta.value_str() { *item = Some(v); true } else { - diagnostic.span_err(meta.span, "incorrect meta item"); + span_err!(diagnostic, meta.span, E0539, "incorrect meta item"); false } }; @@ -462,7 +484,8 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, match tag { "rustc_deprecated" => { if rustc_depr.is_some() { - diagnostic.span_err(item_sp, "multiple rustc_deprecated attributes"); + span_err!(diagnostic, item_sp, E0540, + "multiple rustc_deprecated attributes"); break } @@ -473,8 +496,8 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, "since" => if !get(meta, &mut since) { continue 'outer }, "reason" => if !get(meta, &mut reason) { continue 'outer }, _ => { - diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", - meta.name())); + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(meta.name())); continue 'outer } } @@ -488,18 +511,18 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, }) } (None, _) => { - diagnostic.span_err(attr.span(), "missing 'since'"); + handle_errors(diagnostic, attr.span(), AttrError::MissingSince); continue } _ => { - diagnostic.span_err(attr.span(), "missing 'reason'"); + span_err!(diagnostic, attr.span(), E0543, "missing 'reason'"); continue } } } "unstable" => { if stab.is_some() { - diagnostic.span_err(item_sp, "multiple stability levels"); + handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels); break } @@ -512,8 +535,8 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, "reason" => if !get(meta, &mut reason) { continue 'outer }, "issue" => if !get(meta, &mut issue) { continue 'outer }, _ => { - diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", - meta.name())); + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(meta.name())); continue 'outer } } @@ -528,7 +551,8 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, if let Ok(issue) = issue.parse() { issue } else { - diagnostic.span_err(attr.span(), "incorrect 'issue'"); + span_err!(diagnostic, attr.span(), E0545, + "incorrect 'issue'"); continue } } @@ -538,18 +562,18 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, }) } (None, _, _) => { - diagnostic.span_err(attr.span(), "missing 'feature'"); + handle_errors(diagnostic, attr.span(), AttrError::MissingFeature); continue } _ => { - diagnostic.span_err(attr.span(), "missing 'issue'"); + span_err!(diagnostic, attr.span(), E0547, "missing 'issue'"); continue } } } "stable" => { if stab.is_some() { - diagnostic.span_err(item_sp, "multiple stability levels"); + handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels); break } @@ -560,8 +584,8 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, "feature" => if !get(meta, &mut feature) { continue 'outer }, "since" => if !get(meta, &mut since) { continue 'outer }, _ => { - diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", - meta.name())); + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(meta.name())); continue 'outer } } @@ -578,11 +602,11 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, }) } (None, _) => { - diagnostic.span_err(attr.span(), "missing 'feature'"); + handle_errors(diagnostic, attr.span(), AttrError::MissingFeature); continue } _ => { - diagnostic.span_err(attr.span(), "missing 'since'"); + handle_errors(diagnostic, attr.span(), AttrError::MissingSince); continue } } @@ -590,7 +614,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, _ => unreachable!() } } else { - diagnostic.span_err(attr.span(), "incorrect stability attribute type"); + span_err!(diagnostic, attr.span(), E0548, "incorrect stability attribute type"); continue } } @@ -603,8 +627,9 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } stab.rustc_depr = Some(rustc_depr); } else { - diagnostic.span_err(item_sp, "rustc_deprecated attribute must be paired with \ - either stable or unstable attribute"); + span_err!(diagnostic, item_sp, E0549, + "rustc_deprecated attribute must be paired with \ + either stable or unstable attribute"); } } @@ -627,22 +652,21 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, mark_used(attr); if depr.is_some() { - diagnostic.span_err(item_sp, "multiple deprecated attributes"); + span_err!(diagnostic, item_sp, E0550, "multiple deprecated attributes"); break } depr = if let Some(metas) = attr.meta_item_list() { let get = |meta: &MetaItem, item: &mut Option<InternedString>| { if item.is_some() { - diagnostic.span_err(meta.span, &format!("multiple '{}' items", - meta.name())); + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); return false } if let Some(v) = meta.value_str() { *item = Some(v); true } else { - diagnostic.span_err(meta.span, "incorrect meta item"); + span_err!(diagnostic, meta.span, E0551, "incorrect meta item"); false } }; @@ -654,8 +678,8 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, "since" => if !get(meta, &mut since) { continue 'outer }, "note" => if !get(meta, &mut note) { continue 'outer }, _ => { - diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", - meta.name())); + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(meta.name())); continue 'outer } } @@ -689,7 +713,7 @@ pub fn require_unique_names(diagnostic: &Handler, metas: &[P<MetaItem>]) { if !set.insert(name.clone()) { panic!(diagnostic.span_fatal(meta.span, - &format!("duplicate meta item `{}`", name))); + &format!("duplicate meta item `{}`", name))); } } } @@ -718,8 +742,8 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> Some(ity) => Some(ReprInt(item.span, ity)), None => { // Not a word we recognize - diagnostic.span_err(item.span, - "unrecognized representation hint"); + span_err!(diagnostic, item.span, E0552, + "unrecognized representation hint"); None } } @@ -731,7 +755,8 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> } } // Not a word: - _ => diagnostic.span_err(item.span, "unrecognized enum representation hint") + _ => span_err!(diagnostic, item.span, E0553, + "unrecognized enum representation hint"), } } } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs new file mode 100644 index 00000000000..eb30657bd56 --- /dev/null +++ b/src/libsyntax/diagnostic_list.rs @@ -0,0 +1,54 @@ +// Copyright 2014 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. + +#![allow(non_snake_case)] + +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. +register_long_diagnostics! { + +E0533: r##" +```compile_fail,E0533 +#[export_name] +pub fn something() {} + +fn main() {} +``` +"##, + +} + +register_diagnostics! { + E0534, // expected one argument + E0535, // invalid argument + E0536, // expected 1 cfg-pattern + E0537, // invalid predicate + E0538, // multiple [same] items + E0539, // incorrect meta item + E0540, // multiple rustc_deprecated attributes + E0541, // unknown meta item + E0542, // missing 'since' + E0543, // missing 'reason' + E0544, // multiple stability levels + E0545, // incorrect 'issue' + E0546, // missing 'feature' + E0547, // missing 'issue' + E0548, // incorrect stability attribute type + E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute + E0550, // multiple deprecated attributes + E0551, // incorrect meta item + E0552, // unrecognized representation hint + E0553, // unrecognized enum representation hint + E0554, // #[feature] may not be used on the [] release channel + E0555, // malformed feature attribute, expected #![feature(...)] + E0556, // malformed feature, expected just one word + E0557, // feature has been removed +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d6476fdb2f0..27485ee65fc 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1103,17 +1103,16 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F match attr.meta_item_list() { None => { - span_handler.span_err(attr.span, "malformed feature attribute, \ - expected #![feature(...)]"); + span_err!(span_handler, attr.span, E0555, + "malformed feature attribute, expected #![feature(...)]"); } Some(list) => { for mi in list { let name = match mi.node { ast::MetaItemKind::Word(ref word) => (*word).clone(), _ => { - span_handler.span_err(mi.span, - "malformed feature, expected just \ - one word"); + span_err!(span_handler, mi.span, E0556, + "malformed feature, expected just one word"); continue } }; @@ -1123,7 +1122,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F } else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter() .find(|& &(n, _, _)| name == n) { - span_handler.span_err(mi.span, "feature has been removed"); + span_err!(span_handler, mi.span, E0557, "feature has been removed"); } else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter() .find(|& &(n, _, _)| name == n) { @@ -1179,9 +1178,9 @@ fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, for attr in &krate.attrs { if attr.check_name("feature") { let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); - let ref msg = format!("#[feature] may not be used on the {} release channel", - release_channel); - span_handler.span_err(attr.span, msg); + span_err!(span_handler, attr.span, E0554, + "#[feature] may not be used on the {} release channel", + release_channel); } } } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 652cf68db07..8febf1c49ec 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -33,6 +33,7 @@ #![feature(str_escape)] #![feature(unicode)] #![feature(question_mark)] +#![feature(rustc_diagnostic_macros)] extern crate serialize; extern crate term; @@ -66,6 +67,18 @@ macro_rules! panictry { }) } +#[macro_use] +pub mod diagnostics { + #[macro_use] + pub mod macros; + pub mod plugin; + pub mod metadata; +} + +// NB: This module needs to be declared first so diagnostics are +// registered before they are used. +pub mod diagnostic_list; + pub mod util { pub mod interner; pub mod lev_distance; @@ -80,12 +93,6 @@ pub mod util { pub use self::thin_vec::ThinVec; } -pub mod diagnostics { - pub mod macros; - pub mod plugin; - pub mod metadata; -} - pub mod json; pub mod syntax { @@ -130,3 +137,5 @@ pub mod ext { pub mod macro_rules; } } + +// __build_diagnostic_array! { libsyntax, DIAGNOSTICS } diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 9c6ed991df8..c9d1eb39f0a 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -213,6 +213,7 @@ dependencies = [ "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_llvm 0.0.0", "serialize 0.0.0", diff --git a/src/test/compile-fail/changing-crates.rs b/src/test/compile-fail/changing-crates.rs index 0b420158488..f74855a0849 100644 --- a/src/test/compile-fail/changing-crates.rs +++ b/src/test/compile-fail/changing-crates.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs new file mode 100644 index 00000000000..72a5c5fff60 --- /dev/null +++ b/src/test/compile-fail/const-unsized.rs @@ -0,0 +1,35 @@ +// Copyright 2016 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. + +use std::fmt::Debug; + +const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); +//~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied +//~| NOTE does not have a constant size known at compile-time +//~| NOTE constant expressions must have a statically known size + +const CONST_FOO: str = *"foo"; +//~^ ERROR `str: std::marker::Sized` is not satisfied +//~| NOTE does not have a constant size known at compile-time +//~| NOTE constant expressions must have a statically known size + +static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); +//~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied +//~| NOTE does not have a constant size known at compile-time +//~| NOTE constant expressions must have a statically known size + +static STATIC_BAR: str = *"bar"; +//~^ ERROR `str: std::marker::Sized` is not satisfied +//~| NOTE does not have a constant size known at compile-time +//~| NOTE constant expressions must have a statically known size + +fn main() { + println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); +} diff --git a/src/test/compile-fail/intrinsic-return-address.rs b/src/test/compile-fail/intrinsic-return-address.rs new file mode 100644 index 00000000000..906056896be --- /dev/null +++ b/src/test/compile-fail/intrinsic-return-address.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +#![allow(warnings)] +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +unsafe fn f() { let _ = return_address(); } +//~^ ERROR invalid use of `return_address` intrinsic: function does not use out pointer + +unsafe fn g() -> isize { let _ = return_address(); 0 } +//~^ ERROR invalid use of `return_address` intrinsic: function does not use out pointer + +fn main() {} diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index cbeac774798..b9382520cf9 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -11,6 +11,8 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types + //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied + 0 }; } diff --git a/src/test/compile-fail/stability-attribute-sanity.rs b/src/test/compile-fail/stability-attribute-sanity.rs index 8c7c0c275db..d35f2cbb584 100644 --- a/src/test/compile-fail/stability-attribute-sanity.rs +++ b/src/test/compile-fail/stability-attribute-sanity.rs @@ -15,83 +15,84 @@ #![stable(feature = "rust1", since = "1.0.0")] mod bogus_attribute_types_1 { - #[stable(feature = "a", since = "a", reason)] //~ ERROR unknown meta item 'reason' + #[stable(feature = "a", since = "a", reason)] //~ ERROR unknown meta item 'reason' [E0541] fn f1() { } - #[stable(feature = "a", since)] //~ ERROR incorrect meta item + #[stable(feature = "a", since)] //~ ERROR incorrect meta item [E0539] fn f2() { } - #[stable(feature, since = "a")] //~ ERROR incorrect meta item + #[stable(feature, since = "a")] //~ ERROR incorrect meta item [E0539] fn f3() { } - #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item + #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item [E0539] fn f5() { } - #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item + #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item [E0539] fn f6() { } } mod bogus_attribute_types_2 { - #[unstable] //~ ERROR incorrect stability attribute type + #[unstable] //~ ERROR incorrect stability attribute type [E0548] fn f1() { } - #[unstable = "a"] //~ ERROR incorrect stability attribute type + #[unstable = "a"] //~ ERROR incorrect stability attribute type [E0548] fn f2() { } - #[stable] //~ ERROR incorrect stability attribute type + #[stable] //~ ERROR incorrect stability attribute type [E0548] fn f3() { } - #[stable = "a"] //~ ERROR incorrect stability attribute type + #[stable = "a"] //~ ERROR incorrect stability attribute type [E0548] fn f4() { } #[stable(feature = "a", since = "b")] - #[rustc_deprecated] //~ ERROR incorrect stability attribute type + #[rustc_deprecated] //~ ERROR incorrect stability attribute type [E0548] fn f5() { } #[stable(feature = "a", since = "b")] - #[rustc_deprecated = "a"] //~ ERROR incorrect stability attribute type + #[rustc_deprecated = "a"] //~ ERROR incorrect stability attribute type [E0548] fn f6() { } } mod missing_feature_names { - #[unstable(issue = "0")] //~ ERROR missing 'feature' + #[unstable(issue = "0")] //~ ERROR missing 'feature' [E0546] fn f1() { } - #[unstable(feature = "a")] //~ ERROR missing 'issue' + #[unstable(feature = "a")] //~ ERROR missing 'issue' [E0547] fn f2() { } - #[stable(since = "a")] //~ ERROR missing 'feature' + #[stable(since = "a")] //~ ERROR missing 'feature' [E0546] fn f3() { } } mod missing_version { - #[stable(feature = "a")] //~ ERROR missing 'since' + #[stable(feature = "a")] //~ ERROR missing 'since' [E0542] fn f1() { } #[stable(feature = "a", since = "b")] - #[rustc_deprecated(reason = "a")] //~ ERROR missing 'since' + #[rustc_deprecated(reason = "a")] //~ ERROR missing 'since' [E0542] fn f2() { } } #[unstable(feature = "a", issue = "0")] -#[stable(feature = "a", since = "b")] -fn multiple1() { } //~ ERROR multiple stability levels +#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544] +fn multiple1() { } #[unstable(feature = "a", issue = "0")] -#[unstable(feature = "a", issue = "0")] -fn multiple2() { } //~ ERROR multiple stability levels +#[unstable(feature = "a", issue = "0")] //~ ERROR multiple stability levels [E0544] +fn multiple2() { } #[stable(feature = "a", since = "b")] -#[stable(feature = "a", since = "b")] -fn multiple3() { } //~ ERROR multiple stability levels +#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544] +fn multiple3() { } #[stable(feature = "a", since = "b")] #[rustc_deprecated(since = "b", reason = "text")] #[rustc_deprecated(since = "b", reason = "text")] -fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes +fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540] //~^ ERROR Invalid stability or deprecation version found #[rustc_deprecated(since = "a", reason = "text")] -fn deprecated_without_unstable_or_stable() { } //~ ERROR rustc_deprecated attribute must be paired +fn deprecated_without_unstable_or_stable() { } +//~^ ERROR rustc_deprecated attribute must be paired with either stable or unstable attribute fn main() { } diff --git a/src/test/compile-fail/svh-change-lit.rs b/src/test/compile-fail/svh-change-lit.rs index eb92bcf065d..1638caaa923 100644 --- a/src/test/compile-fail/svh-change-lit.rs +++ b/src/test/compile-fail/svh-change-lit.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-significant-cfg.rs b/src/test/compile-fail/svh-change-significant-cfg.rs index 7c9e0d3a92c..99523ca699f 100644 --- a/src/test/compile-fail/svh-change-significant-cfg.rs +++ b/src/test/compile-fail/svh-change-significant-cfg.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-trait-bound.rs b/src/test/compile-fail/svh-change-trait-bound.rs index 1e6a7232904..dcf4859792d 100644 --- a/src/test/compile-fail/svh-change-trait-bound.rs +++ b/src/test/compile-fail/svh-change-trait-bound.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-type-arg.rs b/src/test/compile-fail/svh-change-type-arg.rs index 73c35ee6f82..7e51ca456b2 100644 --- a/src/test/compile-fail/svh-change-type-arg.rs +++ b/src/test/compile-fail/svh-change-type-arg.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-type-ret.rs b/src/test/compile-fail/svh-change-type-ret.rs index b8908e2cbd1..54ca87d84c1 100644 --- a/src/test/compile-fail/svh-change-type-ret.rs +++ b/src/test/compile-fail/svh-change-type-ret.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-type-static.rs b/src/test/compile-fail/svh-change-type-static.rs index 291e441aa5e..ea90faaf610 100644 --- a/src/test/compile-fail/svh-change-type-static.rs +++ b/src/test/compile-fail/svh-change-type-static.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-use-trait.rs b/src/test/compile-fail/svh-use-trait.rs index ed816a93c52..c0a5a0a17eb 100644 --- a/src/test/compile-fail/svh-use-trait.rs +++ b/src/test/compile-fail/svh-use-trait.rs @@ -22,7 +22,7 @@ extern crate uta; extern crate utb; //~ ERROR: found possibly newer version of crate `uta` which `utb` depends -//~| NOTE: perhaps this crate needs to be recompiled? +//~| NOTE: perhaps that crate needs to be recompiled? //~| NOTE: crate `uta` path #1: //~| NOTE: crate `utb` path #1: diff --git a/src/test/run-make/many-crates-but-no-match/Makefile b/src/test/run-make/many-crates-but-no-match/Makefile index edf8e9df465..0da4af34ef0 100644 --- a/src/test/run-make/many-crates-but-no-match/Makefile +++ b/src/test/run-make/many-crates-but-no-match/Makefile @@ -28,7 +28,7 @@ all: # Ensure crateC fails to compile since A1 is "missing" and A2/A3 hashes do not match $(RUSTC) -L $(A2) -L $(A3) crateC.rs >$(LOG) 2>&1 || true grep "error: found possibly newer version of crate \`crateA\` which \`crateB\` depends on" $(LOG) - grep "note: perhaps this crate needs to be recompiled?" $(LOG) + grep "note: perhaps that crate needs to be recompiled?" $(LOG) grep "note: crate \`crateA\` path #1:" $(LOG) grep "note: crate \`crateA\` path #2:" $(LOG) grep "note: crate \`crateB\` path #1:" $(LOG) diff --git a/src/test/run-pass/intrinsic-return-address.rs b/src/test/run-pass/intrinsic-return-address.rs new file mode 100644 index 00000000000..63aed3f009f --- /dev/null +++ b/src/test/run-pass/intrinsic-return-address.rs @@ -0,0 +1,43 @@ +// Copyright 2012-2014 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. + + +#![feature(intrinsics)] + +use std::ptr; + +struct Point { + x: f32, + y: f32, + z: f32, +} + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +fn f(result: &mut usize) -> Point { + unsafe { + *result = return_address() as usize; + Point { + x: 1.0, + y: 2.0, + z: 3.0, + } + } + +} + +fn main() { + let mut intrinsic_reported_address = 0; + let pt = f(&mut intrinsic_reported_address); + let actual_address = &pt as *const Point as usize; + assert_eq!(intrinsic_reported_address, actual_address); +} diff --git a/src/test/run-pass/issue-34503.rs b/src/test/run-pass/issue-34503.rs new file mode 100644 index 00000000000..e6217243eeb --- /dev/null +++ b/src/test/run-pass/issue-34503.rs @@ -0,0 +1,20 @@ +// Copyright 2016 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. + +fn main() { + struct X; + trait Foo<T> { + fn foo(&self) where (T, Option<T>): Ord {} + fn bar(&self, x: &Option<T>) -> bool + where Option<T>: Ord { *x < *x } + } + impl Foo<X> for () {} + let _ = &() as &Foo<X>; +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 953e060465a..577da5c5af1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1012,8 +1012,7 @@ actual:\n\ // Parse the JSON output from the compiler and extract out the messages. let actual_errors = json::parse_output(&file_name, &proc_res.stderr, &proc_res); - let mut unexpected = 0; - let mut not_found = 0; + let mut unexpected = Vec::new(); let mut found = vec![false; expected_errors.len()]; for actual_error in &actual_errors { let opt_index = @@ -1045,12 +1044,13 @@ actual:\n\ .map_or(String::from("message"), |k| k.to_string()), actual_error.msg)); - unexpected += 1; + unexpected.push(actual_error.clone()); } } } } + let mut not_found = Vec::new(); // anything not yet found is a problem for (index, expected_error) in expected_errors.iter().enumerate() { if !found[index] { @@ -1062,18 +1062,22 @@ actual:\n\ .map_or("message".into(), |k| k.to_string()), expected_error.msg)); - not_found += 1; + not_found.push(expected_error.clone()); } } - if unexpected > 0 || not_found > 0 { + if unexpected.len() > 0 || not_found.len() > 0 { self.error( &format!("{} unexpected errors found, {} expected errors not found", - unexpected, not_found)); + unexpected.len(), not_found.len())); print!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); - println!("actual errors (from JSON output): {:#?}\n", actual_errors); - println!("expected errors (from test file): {:#?}\n", expected_errors); + if unexpected.len() > 0 { + println!("unexpected errors (from JSON output): {:#?}\n", unexpected); + } + if not_found.len() > 0 { + println!("not found errors (from test file): {:#?}\n", not_found); + } panic!(); } } diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 4b74833eaf7..80c37d55975 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -138,22 +138,6 @@ fn check(cache: &mut Cache, return None; } - if file.ends_with("std/sys/ext/index.html") { - return None; - } - - if let Some(file) = file.to_str() { - // FIXME(#31948) - if file.contains("ParseFloatError") { - return None; - } - // weird reexports, but this module is on its way out, so chalk it up to - // "rustdoc weirdness" and move on from there - if file.contains("scoped_tls") { - return None; - } - } - let mut parser = UrlParser::new(); parser.base_url(base); @@ -170,12 +154,24 @@ fn check(cache: &mut Cache, // Search for anything that's the regex 'href[ ]*=[ ]*".*?"' with_attrs_in_source(&contents, " href", |url, i| { + // Ignore external URLs + if url.starts_with("http:") || url.starts_with("https:") || + url.starts_with("javascript:") || url.starts_with("ftp:") || + url.starts_with("irc:") || url.starts_with("data:") { + return; + } // Once we've plucked out the URL, parse it using our base url and - // then try to extract a file path. If either of these fail then we - // just keep going. + // then try to extract a file path. let (parsed_url, path) = match url_to_file_path(&parser, url) { Some((url, path)) => (url, PathBuf::from(path)), - None => return, + None => { + *errors = true; + println!("{}:{}: invalid link - {}", + pretty_file.display(), + i + 1, + url); + return; + } }; // Alright, if we've found a file name then this file had better @@ -197,10 +193,11 @@ fn check(cache: &mut Cache, Ok(res) => res, Err(LoadError::IOError(err)) => panic!(format!("{}", err)), Err(LoadError::BrokenRedirect(target, _)) => { - print!("{}:{}: broken redirect to {}", - pretty_file.display(), - i + 1, - target.display()); + *errors = true; + println!("{}:{}: broken redirect to {}", + pretty_file.display(), + i + 1, + target.display()); return; } Err(LoadError::IsRedirect) => unreachable!(), |
