diff --git a/README.md b/README.md index e656585a898..9463b0e8498 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ $ make && make install If you’d like to build the documentation, it’s almost the same: ```sh -./configure +$ ./configure $ make docs ``` 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 mut hostflags = build.rustc_flags(&compiler.host); + hostflags.extend(flags.clone()); + cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); - let linkflag = format!("-Lnative={}", build.test_helpers_out(target).display()); - cmd.arg("--target-rustcflags").arg(format!("{} {}", flags, linkflag)); - - // 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) { + 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/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> = 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, 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], 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| { 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| { 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]) { 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 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 } } // 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 or the MIT license +// , 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/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/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!(),