diff --git a/RELEASES.md b/RELEASES.md index d634feba33ac5..ecf49278f4b52 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -68,6 +68,13 @@ Misc - [`rustc` will now warn about some incorrect uses of `mem::{uninitialized, zeroed}` that are known to cause undefined behaviour.][63346] +Compatibility Notes +------------------- +- Unfortunately the [`x86_64-unknown-uefi` platform can not be built][62785] + with rustc 1.39.0. +- The [`armv7-unknown-linux-gnueabihf` platform is also known to have + issues][62896] for certain crates such as libc. + [60260]: https://github.com/rust-lang/rust/pull/60260/ [61457]: https://github.com/rust-lang/rust/pull/61457/ [61491]: https://github.com/rust-lang/rust/pull/61491/ @@ -79,7 +86,9 @@ Misc [62735]: https://github.com/rust-lang/rust/pull/62735/ [62766]: https://github.com/rust-lang/rust/pull/62766/ [62784]: https://github.com/rust-lang/rust/pull/62784/ +[62785]: https://github.com/rust-lang/rust/issues/62785/ [62814]: https://github.com/rust-lang/rust/pull/62814/ +[62896]: https://github.com/rust-lang/rust/issues/62896/ [63000]: https://github.com/rust-lang/rust/pull/63000/ [63056]: https://github.com/rust-lang/rust/pull/63056/ [63107]: https://github.com/rust-lang/rust/pull/63107/ diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e27a6bf7da0ac..d9dff77a30e6b 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -18,7 +18,7 @@ use build_helper::{output, t}; use crate::{Compiler, Mode, LLVM_TOOLS}; use crate::channel; -use crate::util::{is_dylib, exe}; +use crate::util::{is_dylib, exe, timeit}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::compile; use crate::tool::{self, Tool}; @@ -91,14 +91,15 @@ impl Step for Docs { let name = pkgname(builder, "rust-docs"); - builder.info(&format!("Dist docs ({})", host)); if !builder.config.docs { - builder.info("\tskipping - docs disabled"); return distdir(builder).join(format!("{}-{}.tar.gz", name, host)); } builder.default_doc(None); + builder.info(&format!("Dist docs ({})", host)); + let _time = timeit(builder); + let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -151,9 +152,7 @@ impl Step for RustcDocs { let name = pkgname(builder, "rustc-docs"); - builder.info(&format!("Dist compiler docs ({})", host)); if !builder.config.compiler_docs { - builder.info("\tskipping - compiler docs disabled"); return distdir(builder).join(format!("{}-{}.tar.gz", name, host)); } @@ -179,6 +178,9 @@ impl Step for RustcDocs { .arg("--component-name=rustc-docs") .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--bulk-dirs=share/doc/rust/html"); + + builder.info(&format!("Dist compiler docs ({})", host)); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); @@ -350,6 +352,7 @@ impl Step for Mingw { } builder.info(&format!("Dist mingw ({})", host)); + let _time = timeit(builder); let name = pkgname(builder, "rust-mingw"); let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -403,7 +406,6 @@ impl Step for Rustc { let compiler = self.compiler; let host = self.compiler.host; - builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host)); let name = pkgname(builder, "rustc"); let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -460,6 +462,9 @@ impl Step for Rustc { .arg(format!("--package-name={}-{}", name, host)) .arg("--component-name=rustc") .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host)); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); builder.remove_dir(&overlay); @@ -662,8 +667,6 @@ impl Step for Std { let target = self.target; let name = pkgname(builder, "rust-std"); - builder.info(&format!("Dist std stage{} ({} -> {})", - compiler.stage, &compiler.host, target)); // The only true set of target libraries came from the build triple, so // let's reduce redundant work by only producing archives from that host. @@ -714,6 +717,10 @@ impl Step for Std { .arg(format!("--package-name={}-{}", name, target)) .arg(format!("--component-name=rust-std-{}", target)) .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info(&format!("Dist std stage{} ({} -> {})", + compiler.stage, &compiler.host, target)); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); distdir(builder).join(format!("{}-{}.tar.gz", name, target)) @@ -754,11 +761,9 @@ impl Step for Analysis { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); - builder.info("Dist analysis"); let name = pkgname(builder, "rust-analysis"); if &compiler.host != builder.config.build { - builder.info("\tskipping, not a build host"); return distdir(builder).join(format!("{}-{}.tar.gz", name, target)); } @@ -786,6 +791,9 @@ impl Step for Analysis { .arg(format!("--package-name={}-{}", name, target)) .arg(format!("--component-name=rust-analysis-{}", target)) .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info("Dist analysis"); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); distdir(builder).join(format!("{}-{}.tar.gz", name, target)) @@ -874,8 +882,6 @@ impl Step for Src { /// Creates the `rust-src` installer component fn run(self, builder: &Builder<'_>) -> PathBuf { - builder.info("Dist src"); - let name = pkgname(builder, "rust-src"); let image = tmpdir(builder).join(format!("{}-image", name)); let _ = fs::remove_dir_all(&image); @@ -930,6 +936,9 @@ impl Step for Src { .arg(format!("--package-name={}", name)) .arg("--component-name=rust-src") .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info("Dist src"); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); @@ -957,8 +966,6 @@ impl Step for PlainSourceTarball { /// Creates the plain source tarball fn run(self, builder: &Builder<'_>) -> PathBuf { - builder.info("Create plain source tarball"); - // Make sure that the root folder of tarball has the correct name let plain_name = format!("{}-src", pkgname(builder, "rustc")); let plain_dst_src = tmpdir(builder).join(&plain_name); @@ -1020,6 +1027,9 @@ impl Step for PlainSourceTarball { .arg("--output").arg(&tarball) .arg("--work-dir=.") .current_dir(tmpdir(builder)); + + builder.info("Create plain source tarball"); + let _time = timeit(builder); builder.run(&mut cmd); distdir(builder).join(&format!("{}.tar.gz", plain_name)) } @@ -1073,7 +1083,6 @@ impl Step for Cargo { let compiler = self.compiler; let target = self.target; - builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/cargo"); let etc = src.join("src/etc"); let release_num = builder.release_num("cargo"); @@ -1126,6 +1135,9 @@ impl Step for Cargo { .arg(format!("--package-name={}-{}", name, target)) .arg("--component-name=cargo") .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); distdir(builder).join(format!("{}-{}.tar.gz", name, target)) } @@ -1161,7 +1173,6 @@ impl Step for Rls { let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/rls"); let release_num = builder.release_num("rls"); let name = pkgname(builder, "rls"); @@ -1210,6 +1221,8 @@ impl Step for Rls { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=rls-preview"); + builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1245,7 +1258,6 @@ impl Step for Clippy { let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/clippy"); let release_num = builder.release_num("clippy"); let name = pkgname(builder, "clippy"); @@ -1299,6 +1311,8 @@ impl Step for Clippy { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=clippy-preview"); + builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1334,7 +1348,6 @@ impl Step for Miri { let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/miri"); let release_num = builder.release_num("miri"); let name = pkgname(builder, "miri"); @@ -1389,6 +1402,8 @@ impl Step for Miri { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=miri-preview"); + builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1423,7 +1438,6 @@ impl Step for Rustfmt { let compiler = self.compiler; let target = self.target; - builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/rustfmt"); let release_num = builder.release_num("rustfmt"); let name = pkgname(builder, "rustfmt"); @@ -1476,6 +1490,8 @@ impl Step for Rustfmt { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=rustfmt-preview"); + builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1576,6 +1592,7 @@ impl Step for Extended { input_tarballs.push(tarball); } + builder.info("building combined installer"); let mut cmd = rust_installer(builder); cmd.arg("combine") .arg("--product-name=Rust") @@ -1587,7 +1604,9 @@ impl Step for Extended { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--input-tarballs").arg(input_tarballs) .arg("--non-installed-overlay").arg(&overlay); + let time = timeit(&builder); builder.run(&mut cmd); + drop(time); let mut license = String::new(); license += &builder.read(&builder.src.join("COPYRIGHT")); @@ -1643,6 +1662,7 @@ impl Step for Extended { }; if target.contains("apple-darwin") { + builder.info("building pkg installer"); let pkg = tmp.join("pkg"); let _ = fs::remove_dir_all(&pkg); @@ -1692,6 +1712,7 @@ impl Step for Extended { pkgname(builder, "rust"), target))) .arg("--package-path").arg(&pkg); + let _time = timeit(builder); builder.run(&mut cmd); } @@ -1742,14 +1763,18 @@ impl Step for Extended { builder.create(&exe.join("LICENSE.txt"), &license); // Generate exe installer + builder.info("building `exe` installer with `iscc`"); let mut cmd = Command::new("iscc"); cmd.arg("rust.iss") + .arg("/Q") .current_dir(&exe); if target.contains("windows-gnu") { cmd.arg("/dMINGW"); } add_env(builder, &mut cmd, target); + let time = timeit(builder); builder.run(&mut cmd); + drop(time); builder.install(&exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)), &distdir(builder), 0o755); @@ -1914,6 +1939,7 @@ impl Step for Extended { builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644); builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644); + builder.info(&format!("building `msi` installer with {:?}", light)); let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target); let mut cmd = Command::new(&light); cmd.arg("-nologo") @@ -1946,6 +1972,7 @@ impl Step for Extended { // ICE57 wrongly complains about the shortcuts cmd.arg("-sice:ICE57"); + let _time = timeit(builder); builder.run(&mut cmd); if !builder.config.dry_run { @@ -2114,6 +2141,7 @@ impl Step for LlvmTools { } builder.info(&format!("Dist LlvmTools ({})", target)); + let _time = timeit(builder); let src = builder.src.join("src/llvm-project/llvm"); let name = pkgname(builder, "llvm-tools"); diff --git a/src/etc/installer/exe/rust.iss b/src/etc/installer/exe/rust.iss index c22d60b6c5df1..70648beac38b0 100644 --- a/src/etc/installer/exe/rust.iss +++ b/src/etc/installer/exe/rust.iss @@ -25,9 +25,9 @@ SourceDir=.\ OutputBaseFilename={#CFG_PACKAGE_NAME}-{#CFG_BUILD} DefaultDirName={sd}\Rust -Compression=lzma2/ultra -InternalCompressLevel=ultra -SolidCompression=true +Compression=lzma2/normal +InternalCompressLevel=normal +SolidCompression=no ChangesEnvironment=true ChangesAssociations=no diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index a471ccc6f5b48..a2e378f7b1db4 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -152,7 +152,7 @@ - + diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index dd290572d7bb7..5906a6388a8bd 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -7,7 +7,7 @@ use crate::lint::{LintPass, LateLintPass, LintArray}; use crate::middle::stability; use crate::session::Session; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use syntax::ast; use syntax::source_map::Span; use syntax::symbol::Symbol; @@ -524,7 +524,7 @@ pub(crate) fn add_elided_lifetime_in_path_suggestion( }; db.span_suggestion( replace_span, - &format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }), + &format!("indicate the anonymous lifetime{}", pluralise!(n)), suggestion, Applicability::MachineApplicable ); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8836a632a7ca8..d833a34385b2d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -17,7 +17,7 @@ use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use crate::rustc::lint; use crate::session::Session; use crate::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet}; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use rustc_macros::HashStable; use std::borrow::Cow; use std::cell::Cell; @@ -3047,7 +3047,7 @@ pub fn report_missing_lifetime_specifiers( span, E0106, "missing lifetime specifier{}", - if count > 1 { "s" } else { "" } + pluralise!(count) ) } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 723855c7c29cf..e566a2ae42e58 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1295,6 +1295,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show extended diagnostic help"), terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], "set the current terminal width"), + panic_abort_tests: bool = (false, parse_bool, [TRACKED], + "support compiling tests with panic=abort"), continue_parse_after_error: bool = (false, parse_bool, [TRACKED], "attempt to recover from parse errors (experimental)"), dep_tasks: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index b6f0addd77107..bc6bcb1f76f96 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -378,7 +378,15 @@ fn orphan_check_trait_ref<'tcx>( // Let Ti be the first such type. // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) // - for input_ty in trait_ref.input_types() { + fn uncover_fundamental_ty(ty: Ty<'_>) -> Vec> { + if fundamental_ty(ty) { + ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(ty)).collect() + } else { + vec![ty] + } + } + + for input_ty in trait_ref.input_types().flat_map(uncover_fundamental_ty) { debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); if ty_is_local(tcx, input_ty, in_crate) { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 1d87484ef09be..c9018f1c290d2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -33,7 +33,7 @@ use crate::ty::subst::Subst; use crate::ty::SubtypePredicate; use crate::util::nodemap::{FxHashMap, FxHashSet}; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use std::fmt; use syntax::ast; use syntax::symbol::{sym, kw}; @@ -1214,7 +1214,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => format!("{} {}argument{}", arg_length, if distinct && arg_length > 1 { "distinct " } else { "" }, - if arg_length == 1 { "" } else { "s" }), + pluralise!(arg_length)) } }; diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 62910ec320494..5409cbc4129f0 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -196,7 +196,7 @@ impl<'tcx> ty::TyS<'tcx> { let n = tcx.lift_to_global(&n).unwrap(); match n.try_eval_usize(tcx, ty::ParamEnv::empty()) { Some(n) => { - format!("array of {} element{}", n, if n != 1 { "s" } else { "" }).into() + format!("array of {} element{}", n, pluralise!(n)).into() } None => "array".into(), } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index e8e8da6733471..032bd2c02561d 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -446,6 +446,8 @@ fn configure_and_expand_inner<'a>( &mut krate, sess.diagnostic(), &sess.features_untracked(), + sess.panic_strategy(), + sess.opts.debugging_opts.panic_abort_tests, ) }); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index c3975098351af..2d4af2f606a2c 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -9,7 +9,7 @@ use lint::{LintPass, EarlyLintPass, LateLintPass}; use syntax::ast; use syntax::attr; -use syntax::errors::Applicability; +use syntax::errors::{Applicability, pluralise}; use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use syntax::print::pprust; use syntax::symbol::{kw, sym}; @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } let ty = cx.tables.expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1); let mut fn_warned = false; let mut op_warned = false; @@ -135,7 +135,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { span: Span, descr_pre: &str, descr_post: &str, - plural: bool, + plural_len: usize, ) -> bool { if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( cx.tcx.hir().get_module_parent(expr.hir_id), ty) @@ -143,13 +143,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return true; } - let plural_suffix = if plural { "s" } else { "" }; + let plural_suffix = pluralise!(plural_len); match ty.sty { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); let descr_pre = &format!("{}boxed ", descr_pre); - check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural) + check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len) } ty::Adt(def, _) => { check_must_use_def(cx, def.did, span, descr_pre, descr_post) @@ -202,7 +202,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { let descr_post = &format!(" in tuple element {}", i); let span = *spans.get(i).unwrap_or(&span); - if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) { + if check_must_use_ty( + cx, + ty, + expr, + span, + descr_pre, + descr_post, + plural_len + ) { has_emitted = true; } } @@ -216,7 +224,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { descr_pre, plural_suffix, ); - check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true) + check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1) } // Otherwise, we don't lint, to avoid false positives. _ => false, diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 96d44b4b4c0dc..0d85be83e12e0 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -26,6 +26,8 @@ use crate::Resolver; use crate::resolve_imports::ImportDirectiveSubclass; +use errors::pluralise; + use rustc::util::nodemap::NodeMap; use rustc::{lint, ty}; use rustc_data_structures::fx::FxHashSet; @@ -295,7 +297,7 @@ impl Resolver<'_> { }).collect::>(); span_snippets.sort(); let msg = format!("unused import{}{}", - if len > 1 { "s" } else { "" }, + pluralise!(len), if !span_snippets.is_empty() { format!(": {}", span_snippets.join(", ")) } else { diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 0c86d8494fde8..df8bd3fa75e14 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -424,7 +424,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { } else { err.note("did you mean to use one of the enum's variants?"); } - }, + } (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { if let Some((ctor_def, ctor_vis)) = self.r.struct_constructors.get(&def_id).cloned() { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e77e8290f1faa..360343169bc3d 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -11,7 +11,7 @@ use crate::{Resolver, ResolutionError, Segment, ModuleKind}; use crate::{names_to_string, module_to_string}; use crate::diagnostics::Suggestion; -use errors::Applicability; +use errors::{Applicability, pluralise}; use rustc_data_structures::ptr_key::PtrKey; use rustc::ty; @@ -728,7 +728,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let msg = format!( "unresolved import{} {}", - if paths.len() > 1 { "s" } else { "" }, + pluralise!(paths.len()), paths.join(", "), ); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 09e6b76900396..718d12484f741 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1346,7 +1346,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, E0191, "the value of the associated type{} {} must be specified", - if associated_types.len() == 1 { "" } else { "s" }, + pluralise!(associated_types.len()), names, ); let (suggest, potential_assoc_types_spans) = diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 049f2eb16bb00..1ae50b8cb2883 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -17,7 +17,7 @@ use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; use crate::astconv::AstConv as _; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use syntax::ast; use syntax::symbol::{Symbol, kw, sym}; use syntax::source_map::Span; @@ -1178,7 +1178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { struct_span_err!(tcx.sess, span, E0063, "missing field{} {}{} in initializer of `{}`", - if remaining_fields.len() == 1 { "" } else { "s" }, + pluralise!(remaining_fields.len()), remaining_fields_names, truncated_fields_error, adt_ty) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 3e45b1e98d4ec..74e4f28255b16 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -5,7 +5,7 @@ use crate::check::FnCtxt; use crate::middle::lang_items::FnOnceTraitLangItem; use crate::namespace::Namespace; use crate::util::nodemap::FxHashSet; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use rustc::hir::{self, ExprKind, Node, QPath}; use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; @@ -560,7 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let help = format!("{an}other candidate{s} {were} found in the following \ trait{s}, perhaps add a `use` for {one_of_them}:", an = if candidates.len() == 1 {"an" } else { "" }, - s = if candidates.len() == 1 { "" } else { "s" }, + s = pluralise!(candidates.len()), were = if candidates.len() == 1 { "was" } else { "were" }, one_of_them = if candidates.len() == 1 { "it" diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0eeeee01c82f1..7ff8f9c95c89c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,7 +88,7 @@ pub mod intrinsic; mod op; use crate::astconv::{AstConv, PathSeg}; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise}; use rustc::hir::{self, ExprKind, GenericArg, ItemKind, Node, PatKind, QPath}; use rustc::hir::def::{CtorOf, Res, DefKind}; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -4935,5 +4935,5 @@ fn fatally_break_rust(sess: &Session) { } fn potentially_plural_count(count: usize, word: &str) -> String { - format!("{} {}{}", count, word, if count == 1 { "" } else { "s" }) + format!("{} {}{}", count, word, pluralise!(count)) } diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 8502b89de1469..d93a4052cd393 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1,6 +1,6 @@ use crate::check::FnCtxt; use crate::util::nodemap::FxHashMap; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use rustc::hir::{self, PatKind, Pat, HirId}; use rustc::hir::def::{Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -684,8 +684,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn e0023(&self, pat_span: Span, res: Res, subpats: &'tcx [P], fields: &[ty::FieldDef]) { - let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; - let fields_ending = if fields.len() == 1 { "" } else { "s" }; + let subpats_ending = pluralise!(subpats.len()); + let fields_ending = pluralise!(fields.len()); let res_span = self.tcx.def_span(res.def_id()); struct_span_err!( self.tcx.sess, @@ -1103,10 +1103,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0527, "pattern requires {} element{} but array has {}", min_len, - if min_len != 1 { "s" } else { "" }, + pluralise!(min_len), size, ) - .span_label(span, format!("expected {} element{}", size, if size != 1 { "s" } else { "" })) + .span_label(span, format!("expected {} element{}", size, pluralise!(size))) .emit(); } @@ -1117,14 +1117,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0528, "pattern requires at least {} element{} but array has {}", min_len, - if min_len != 1 { "s" } else { "" }, + pluralise!(min_len), size, ).span_label( span, format!( "pattern cannot match array of {} element{}", size, - if size != 1 { "s" } else { "" }, + pluralise!(size), ), ).emit(); } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 23735727fe8cf..f9c07e3a2e4ff 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -8,6 +8,7 @@ use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use smallvec::{smallvec, SmallVec}; +use errors::pluralise; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use syntax_pos::hygiene::{ExpnId, Transparency}; @@ -348,10 +349,10 @@ impl LockstepIterSize { "meta-variable `{}` repeats {} time{}, but `{}` repeats {} time{}", l_id, l_len, - if l_len != 1 { "s" } else { "" }, + pluralise!(l_len), r_id, r_len, - if r_len != 1 { "s" } else { "" }, + pluralise!(r_len), ); LockstepIterSize::Contradiction(msg) } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index b74f2492c351f..2d7f4f71ca4ee 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -11,7 +11,7 @@ use crate::ptr::P; use crate::symbol::{kw, sym}; use crate::ThinVec; use crate::util::parser::AssocOp; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise}; use rustc_data_structures::fx::FxHashSet; use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; @@ -532,15 +532,15 @@ impl<'a> Parser<'a> { self.eat_to_tokens(&[&end]); let span = lo.until(self.token.span); - let plural = number_of_gt > 1 || number_of_shr >= 1; + let total_num_of_gt = number_of_gt + number_of_shr * 2; self.diagnostic() .struct_span_err( span, - &format!("unmatched angle bracket{}", if plural { "s" } else { "" }), + &format!("unmatched angle bracket{}", pluralise!(total_num_of_gt)), ) .span_suggestion( span, - &format!("remove extra angle bracket{}", if plural { "s" } else { "" }), + &format!("remove extra angle bracket{}", pluralise!(total_num_of_gt)), String::new(), Applicability::MachineApplicable, ) diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 31b28443abbc3..14a93d986b305 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -66,6 +66,10 @@ pub(super) enum LhsExpr { } impl From>> for LhsExpr { + /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)` + /// and `None` into `LhsExpr::NotYetParsed`. + /// + /// This conversion does not allocate. fn from(o: Option>) -> Self { if let Some(attrs) = o { LhsExpr::AttributesParsed(attrs) @@ -76,6 +80,9 @@ impl From>> for LhsExpr { } impl From> for LhsExpr { + /// Converts the `expr: P` into `LhsExpr::AlreadyParsed(expr)`. + /// + /// This conversion does not allocate. fn from(expr: P) -> Self { LhsExpr::AlreadyParsed(expr) } diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index d4b13cc2e0121..dcd3c64801742 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -9,7 +9,7 @@ use crate::symbol::kw; use std::mem; use log::debug; -use errors::{Applicability}; +use errors::{Applicability, pluralise}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] @@ -347,20 +347,19 @@ impl<'a> Parser<'a> { let span = lo.with_hi( lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count) ); - let plural = snapshot.unmatched_angle_bracket_count > 1; self.diagnostic() .struct_span_err( span, &format!( "unmatched angle bracket{}", - if plural { "s" } else { "" } + pluralise!(snapshot.unmatched_angle_bracket_count) ), ) .span_suggestion( span, &format!( "remove extra angle bracket{}", - if plural { "s" } else { "" } + pluralise!(snapshot.unmatched_angle_bracket_count) ), String::new(), Applicability::MachineApplicable, diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index 465e31ac57e64..5697edd8e4867 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -11,7 +11,7 @@ use crate::symbol::{kw}; use rustc_target::spec::abi::Abi; -use errors::{Applicability}; +use errors::{Applicability, pluralise}; /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, /// `IDENT<::AssocTy>`. @@ -397,7 +397,7 @@ impl<'a> Parser<'a> { } if !negative_bounds.is_empty() || was_negative { - let plural = negative_bounds.len() > 1; + let negative_bounds_len = negative_bounds.len(); let last_span = negative_bounds.last().map(|sp| *sp); let mut err = self.struct_span_err( negative_bounds, @@ -420,7 +420,7 @@ impl<'a> Parser<'a> { } err.span_suggestion_hidden( bound_list, - &format!("remove the trait bound{}", if plural { "s" } else { "" }), + &format!("remove the trait bound{}", pluralise!(negative_bounds_len)), new_bound_list, Applicability::MachineApplicable, ); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index bf36c0d2f5658..27927c3c67593 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1657,9 +1657,18 @@ impl<'a> State<'a> { } } ast::StmtKind::Semi(ref expr) => { - self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false); - self.s.word(";"); + match expr.node { + // Filter out empty `Tup` exprs created for the `redundant_semicolon` + // lint, as they shouldn't be visible and interact poorly + // with proc macros. + ast::ExprKind::Tup(ref exprs) if exprs.is_empty() + && expr.attrs.is_empty() => (), + _ => { + self.space_if_not_bol(); + self.print_expr_outer_attr_style(expr, false); + self.s.word(";"); + } + } } ast::StmtKind::Mac(ref mac) => { let (ref mac, style, ref attrs) = **mac; diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 46c7cbb83de90..26455df17b896 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -5,6 +5,7 @@ use fmt_macros as parse; use errors::DiagnosticBuilder; use errors::Applicability; +use errors::pluralise; use syntax::ast; use syntax::ext::base::{self, *}; @@ -299,7 +300,7 @@ impl<'a, 'b> Context<'a, 'b> { &format!( "{} positional argument{} in format string, but {}", count, - if count != 1 { "s" } else { "" }, + pluralise!(count), self.describe_num_args(), ), ); diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index 56de0c97f81c0..158a7c2df8a0f 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -2,6 +2,7 @@ use log::debug; use smallvec::{smallvec, SmallVec}; +use rustc_target::spec::PanicStrategy; use syntax::ast::{self, Ident}; use syntax::attr; use syntax::entry::{self, EntryPointType}; @@ -25,6 +26,7 @@ struct Test { struct TestCtxt<'a> { ext_cx: ExtCtxt<'a>, + panic_strategy: PanicStrategy, def_site: Span, test_cases: Vec, reexport_test_harness_main: Option, @@ -40,6 +42,8 @@ pub fn inject( krate: &mut ast::Crate, span_diagnostic: &errors::Handler, features: &Features, + panic_strategy: PanicStrategy, + enable_panic_abort_tests: bool, ) { // Check for #![reexport_test_harness_main = "some_name"] which gives the // main test function the name `some_name` without hygiene. This needs to be @@ -52,9 +56,13 @@ pub fn inject( // even in non-test builds let test_runner = get_test_runner(span_diagnostic, &krate); + let panic_strategy = match (panic_strategy, enable_panic_abort_tests) { + (PanicStrategy::Abort, true) => PanicStrategy::Abort, + _ => PanicStrategy::Unwind, + }; if should_test { generate_test_harness(sess, resolver, reexport_test_harness_main, - krate, features, test_runner) + krate, features, panic_strategy, test_runner) } } @@ -183,6 +191,7 @@ fn generate_test_harness(sess: &ParseSess, reexport_test_harness_main: Option, krate: &mut ast::Crate, features: &Features, + panic_strategy: PanicStrategy, test_runner: Option) { let mut econfig = ExpansionConfig::default("test".to_string()); econfig.features = Some(features); @@ -203,6 +212,7 @@ fn generate_test_harness(sess: &ParseSess, let cx = TestCtxt { ext_cx, + panic_strategy, def_site, test_cases: Vec::new(), reexport_test_harness_main, @@ -248,9 +258,14 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { let ecx = &cx.ext_cx; let test_id = Ident::new(sym::test, sp); + let runner_name = match cx.panic_strategy { + PanicStrategy::Unwind => "test_main_static", + PanicStrategy::Abort => "test_main_static_abort", + }; + // test::test_main_static(...) let mut test_runner = cx.test_runner.clone().unwrap_or( - ecx.path(sp, vec![test_id, ecx.ident_of("test_main_static", sp)])); + ecx.path(sp, vec![test_id, ecx.ident_of(runner_name, sp)])); test_runner.span = sp; diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs index cc30b06e5ec38..f431c9de7f118 100644 --- a/src/libtest/formatters/mod.rs +++ b/src/libtest/formatters/mod.rs @@ -21,3 +21,12 @@ pub(crate) trait OutputFormatter { ) -> io::Result<()>; fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result; } + +pub(crate) fn write_stderr_delimiter(test_output: &mut Vec, test_name: &TestName) { + match test_output.last() { + Some(b'\n') => (), + Some(_) => test_output.push(b'\n'), + None => (), + } + write!(test_output, "---- {} stderr ----\n", test_name).unwrap(); +} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 09d5fcc89520e..2a2f32f97162d 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -21,7 +21,8 @@ #![unstable(feature = "test", issue = "50297")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] #![feature(asm)] -#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc, rustc_private))] +#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] +#![feature(rustc_private)] #![feature(nll)] #![feature(set_stdio)] #![feature(panic_unwind)] @@ -34,16 +35,6 @@ use getopts; extern crate libc; use term; -// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind -// on aarch64-pc-windows-msvc, or thumbv7a-pc-windows-msvc -// so we don't link libtest against libunwind (for the time being) -// even though it means that libtest won't be fully functional on -// these platforms. -// -// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437 -#[cfg(not(all(windows, any(target_arch = "aarch64", target_arch = "arm"))))] -extern crate panic_unwind; - pub use self::ColorConfig::*; use self::NamePadding::*; use self::OutputLocation::*; @@ -61,10 +52,10 @@ use std::fmt; use std::fs::File; use std::io; use std::io::prelude::*; -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo}; use std::path::PathBuf; use std::process; -use std::process::Termination; +use std::process::{ExitStatus, Command, Termination}; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; use std::thread; @@ -76,13 +67,21 @@ mod tests; const TEST_WARN_TIMEOUT_S: u64 = 60; const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode +const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE"; + +// Return codes for secondary process. +// Start somewhere other than 0 so we know the return code means what we think +// it means. +const TR_OK: i32 = 50; +const TR_FAILED: i32 = 51; + // to be used by rustc to compile tests in libtest pub mod test { pub use crate::{ assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static, - Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic, - StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts, - TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, + Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, RunStrategy, + ShouldPanic, StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, + TestOpts, TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, }; } @@ -257,12 +256,14 @@ impl Metric { #[derive(Copy, Clone, Debug)] pub struct Options { display_output: bool, + panic_abort: bool, } impl Options { pub fn new() -> Options { Options { display_output: false, + panic_abort: false, } } @@ -270,6 +271,11 @@ impl Options { self.display_output = display_output; self } + + pub fn panic_abort(mut self, panic_abort: bool) -> Options { + self.panic_abort = panic_abort; + self + } } // The default console test runner. It accepts the command line @@ -303,32 +309,66 @@ pub fn test_main(args: &[String], tests: Vec, options: Option is used in order to effect ownership-transfer -// semantics into parallel test runners, which in turn requires a Vec<> -// rather than a &[]. +/// A variant optimized for invocation with a static test vector. +/// This will panic (intentionally) when fed any dynamic tests. +/// +/// This is the entry point for the main function generated by `rustc --test` +/// when panic=unwind. pub fn test_main_static(tests: &[&TestDescAndFn]) { let args = env::args().collect::>(); - let owned_tests = tests - .iter() - .map(|t| match t.testfn { - StaticTestFn(f) => TestDescAndFn { - testfn: StaticTestFn(f), - desc: t.desc.clone(), - }, - StaticBenchFn(f) => TestDescAndFn { - testfn: StaticBenchFn(f), - desc: t.desc.clone(), - }, - _ => panic!("non-static tests passed to test::test_main_static"), - }) - .collect(); + let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect(); test_main(&args, owned_tests, None) } +/// A variant optimized for invocation with a static test vector. +/// This will panic (intentionally) when fed any dynamic tests. +/// +/// Runs tests in panic=abort mode, which involves spawning subprocesses for +/// tests. +/// +/// This is the entry point for the main function generated by `rustc --test` +/// when panic=abort. +pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { + // If we're being run in SpawnedSecondary mode, run the test here. run_test + // will then exit the process. + if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) { + let test = tests + .iter() + .filter(|test| test.desc.name.as_slice() == name) + .map(make_owned_test) + .next() + .expect("couldn't find a test with the provided name"); + let TestDescAndFn { desc, testfn } = test; + let testfn = match testfn { + StaticTestFn(f) => f, + _ => panic!("only static tests are supported"), + }; + run_test_in_spawned_subprocess(desc, Box::new(testfn)); + } + + let args = env::args().collect::>(); + let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect(); + test_main(&args, owned_tests, Some(Options::new().panic_abort(true))) +} + +/// Clones static values for putting into a dynamic vector, which test_main() +/// needs to hand out ownership of tests to parallel test runners. +/// +/// This will panic when fed any dynamic tests, because they cannot be cloned. +fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn { + match test.testfn { + StaticTestFn(f) => TestDescAndFn { + testfn: StaticTestFn(f), + desc: test.desc.clone(), + }, + StaticBenchFn(f) => TestDescAndFn { + testfn: StaticBenchFn(f), + desc: test.desc.clone(), + }, + _ => panic!("non-static tests passed to test::test_main_static"), + } +} + /// Invoked when unit tests terminate. Should panic if the unit /// Tests is considered a failure. By default, invokes `report()` /// and checks for a `0` result. @@ -1021,6 +1061,18 @@ impl Write for Sink { } } +#[derive(Clone, Copy)] +pub enum RunStrategy { + /// Runs the test in the current process, and sends the result back over the + /// supplied channel. + InProcess, + + /// Spawns a subprocess to run the test, and sends the result back over the + /// supplied channel. Requires argv[0] to exist and point to the binary + /// that's currently running. + SpawnPrimary, +} + pub fn run_tests(opts: &TestOpts, tests: Vec, mut callback: F) -> io::Result<()> where F: FnMut(TestEvent) -> io::Result<()>, @@ -1068,6 +1120,11 @@ where let mut pending = 0; let (tx, rx) = channel::(); + let run_strategy = if opts.options.panic_abort { + RunStrategy::SpawnPrimary + } else { + RunStrategy::InProcess + }; let mut running_tests: TestMap = HashMap::default(); @@ -1104,7 +1161,7 @@ where while !remaining.is_empty() { let test = remaining.pop().unwrap(); callback(TeWait(test.desc.clone()))?; - run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::No); + run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No); let (test, result, stdout) = rx.recv().unwrap(); callback(TeResult(test, result, stdout))?; } @@ -1115,7 +1172,7 @@ where let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); running_tests.insert(test.desc.clone(), timeout); callback(TeWait(test.desc.clone()))?; //here no pad - run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::Yes); + run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes); pending += 1; } @@ -1147,7 +1204,7 @@ where // All benchmarks run at the end, in serial. for b in filtered_benchs { callback(TeWait(b.desc.clone()))?; - run_test(opts, false, b, tx.clone(), Concurrent::No); + run_test(opts, false, b, run_strategy, tx.clone(), Concurrent::No); let (test, result, stdout) = rx.recv().unwrap(); callback(TeResult(test, result, stdout))?; } @@ -1374,54 +1431,36 @@ pub fn run_test( opts: &TestOpts, force_ignore: bool, test: TestDescAndFn, + strategy: RunStrategy, monitor_ch: Sender, concurrency: Concurrent, ) { let TestDescAndFn { desc, testfn } = test; - let ignore_because_panic_abort = cfg!(target_arch = "wasm32") + let ignore_because_no_process_support = cfg!(target_arch = "wasm32") && !cfg!(target_os = "emscripten") && desc.should_panic != ShouldPanic::No; - if force_ignore || desc.ignore || ignore_because_panic_abort { + if force_ignore || desc.ignore || ignore_because_no_process_support { monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap(); return; } fn run_test_inner( desc: TestDesc, - monitor_ch: Sender, nocapture: bool, + strategy: RunStrategy, + monitor_ch: Sender, testfn: Box, concurrency: Concurrent, ) { - // Buffer for capturing standard I/O - let data = Arc::new(Mutex::new(Vec::new())); - let data2 = data.clone(); - let name = desc.name.clone(); - let runtest = move || { - let oldio = if !nocapture { - Some(( - io::set_print(Some(Box::new(Sink(data2.clone())))), - io::set_panic(Some(Box::new(Sink(data2)))), - )) - } else { - None - }; - - let result = catch_unwind(AssertUnwindSafe(testfn)); - - if let Some((printio, panicio)) = oldio { - io::set_print(printio); - io::set_panic(panicio); - }; - let test_result = calc_result(&desc, result); - let stdout = data.lock().unwrap().to_vec(); - monitor_ch - .send((desc.clone(), test_result, stdout)) - .unwrap(); + let runtest = move || { + match strategy { + RunStrategy::InProcess => run_test_in_process(desc, nocapture, testfn, monitor_ch), + RunStrategy::SpawnPrimary => spawn_test_subprocess(desc, monitor_ch), + } }; // If the platform is single-threaded we're just going to run @@ -1438,26 +1477,29 @@ pub fn run_test( match testfn { DynBenchFn(bencher) => { + // Benchmarks aren't expected to panic, so we run them all in-process. crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { bencher.run(harness) }); } StaticBenchFn(benchfn) => { + // Benchmarks aren't expected to panic, so we run them all in-process. crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { (benchfn.clone())(harness) }); } DynTestFn(f) => { + match strategy { + RunStrategy::InProcess => (), + _ => panic!("Cannot run dynamic test fn out-of-process"), + }; + let cb = move || __rust_begin_short_backtrace(f); + run_test_inner(desc, opts.nocapture, strategy, monitor_ch, Box::new(cb), concurrency); + } + StaticTestFn(f) => { let cb = move || __rust_begin_short_backtrace(f); - run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb), concurrency) + run_test_inner(desc, opts.nocapture, strategy, monitor_ch, Box::new(cb), concurrency); } - StaticTestFn(f) => run_test_inner( - desc, - monitor_ch, - opts.nocapture, - Box::new(move || __rust_begin_short_backtrace(f)), - concurrency, - ), } } @@ -1467,7 +1509,9 @@ fn __rust_begin_short_backtrace(f: F) { f() } -fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> TestResult { +fn calc_result<'a>(desc: &TestDesc, + task_result: Result<(), &'a (dyn Any + 'static + Send)>) +-> TestResult { match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk, (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => { @@ -1492,6 +1536,130 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> } } +fn get_result_from_exit_code(desc: &TestDesc, code: i32) -> TestResult { + match (desc.allow_fail, code) { + (_, TR_OK) => TrOk, + (true, TR_FAILED) => TrAllowedFail, + (false, TR_FAILED) => TrFailed, + (_, _) => TrFailedMsg(format!("got unexpected return code {}", code)), + } +} + +fn run_test_in_process(desc: TestDesc, + nocapture: bool, + testfn: Box, + monitor_ch: Sender) { + // Buffer for capturing standard I/O + let data = Arc::new(Mutex::new(Vec::new())); + + let oldio = if !nocapture { + Some(( + io::set_print(Some(Box::new(Sink(data.clone())))), + io::set_panic(Some(Box::new(Sink(data.clone())))), + )) + } else { + None + }; + + let result = catch_unwind(AssertUnwindSafe(testfn)); + + if let Some((printio, panicio)) = oldio { + io::set_print(printio); + io::set_panic(panicio); + } + + let test_result = match result { + Ok(()) => calc_result(&desc, Ok(())), + Err(e) => calc_result(&desc, Err(e.as_ref())), + }; + let stdout = data.lock().unwrap().to_vec(); + monitor_ch.send((desc.clone(), test_result, stdout)).unwrap(); +} + +fn spawn_test_subprocess(desc: TestDesc, monitor_ch: Sender) { + let (result, test_output) = (|| { + let args = env::args().collect::>(); + let current_exe = &args[0]; + let output = match Command::new(current_exe) + .env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice()) + .output() { + Ok(out) => out, + Err(e) => { + let err = format!("Failed to spawn {} as child for test: {:?}", args[0], e); + return (TrFailed, err.into_bytes()); + } + }; + + let std::process::Output { stdout, stderr, status } = output; + let mut test_output = stdout; + formatters::write_stderr_delimiter(&mut test_output, &desc.name); + test_output.extend_from_slice(&stderr); + + let result = match (|| -> Result { + let exit_code = get_exit_code(status)?; + Ok(get_result_from_exit_code(&desc, exit_code)) + })() { + Ok(r) => r, + Err(e) => { + write!(&mut test_output, "Unexpected error: {}", e).unwrap(); + TrFailed + } + }; + + (result, test_output) + })(); + + monitor_ch.send((desc.clone(), result, test_output)).unwrap(); +} + +fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box) -> ! { + let builtin_panic_hook = panic::take_hook(); + let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| { + let test_result = match panic_info { + Some(info) => calc_result(&desc, Err(info.payload())), + None => calc_result(&desc, Ok(())), + }; + + // We don't support serializing TrFailedMsg, so just + // print the message out to stderr. + if let TrFailedMsg(msg) = &test_result { + eprintln!("{}", msg); + } + + if let Some(info) = panic_info { + builtin_panic_hook(info); + } + + if let TrOk = test_result { + process::exit(TR_OK); + } else { + process::exit(TR_FAILED); + } + }); + let record_result2 = record_result.clone(); + panic::set_hook(Box::new(move |info| record_result2(Some(&info)))); + testfn(); + record_result(None); + unreachable!("panic=abort callback should have exited the process") +} + +#[cfg(not(unix))] +fn get_exit_code(status: ExitStatus) -> Result { + status.code().ok_or("received no exit code from child process".into()) +} + +#[cfg(unix)] +fn get_exit_code(status: ExitStatus) -> Result { + use std::os::unix::process::ExitStatusExt; + match status.code() { + Some(code) => Ok(code), + None => match status.signal() { + Some(signal) => Err(format!("child process exited with signal {}", signal)), + None => Err("child process exited with unknown signal".into()), + } + } +} + #[derive(Clone, PartialEq)] pub struct MetricMap(BTreeMap); @@ -1640,7 +1808,9 @@ where } pub mod bench { - use super::{BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult}; + use super::{ + BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult + }; use crate::stats; use std::cmp; use std::io; @@ -1658,12 +1828,10 @@ pub mod bench { }; let data = Arc::new(Mutex::new(Vec::new())); - let data2 = data.clone(); - let oldio = if !nocapture { Some(( - io::set_print(Some(Box::new(Sink(data2.clone())))), - io::set_panic(Some(Box::new(Sink(data2)))), + io::set_print(Some(Box::new(Sink(data.clone())))), + io::set_panic(Some(Box::new(Sink(data.clone())))), )) } else { None @@ -1674,7 +1842,7 @@ pub mod bench { if let Some((printio, panicio)) = oldio { io::set_print(printio); io::set_panic(panicio); - }; + } let test_result = match result { //bs.bench(f) { diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs index afc4217ec1ba2..2c4320df12565 100644 --- a/src/libtest/tests.rs +++ b/src/libtest/tests.rs @@ -1,7 +1,7 @@ use super::*; use crate::test::{ - filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, + filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, RunStrategy, ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg, TrIgnored, TrOk, }; @@ -66,7 +66,7 @@ pub fn do_not_run_ignored_tests() { testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); let (_, res, _) = rx.recv().unwrap(); assert!(res != TrOk); } @@ -84,7 +84,7 @@ pub fn ignored_tests_result_in_ignored() { testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); let (_, res, _) = rx.recv().unwrap(); assert!(res == TrIgnored); } @@ -104,7 +104,7 @@ fn test_should_panic() { testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); let (_, res, _) = rx.recv().unwrap(); assert!(res == TrOk); } @@ -124,7 +124,7 @@ fn test_should_panic_good_message() { testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); let (_, res, _) = rx.recv().unwrap(); assert!(res == TrOk); } @@ -146,7 +146,7 @@ fn test_should_panic_bad_message() { testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); let (_, res, _) = rx.recv().unwrap(); assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected))); } @@ -164,7 +164,7 @@ fn test_should_panic_but_succeeds() { testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); let (_, res, _) = rx.recv().unwrap(); assert!(res == TrFailed); } diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs new file mode 100644 index 0000000000000..b08fedc5e11c2 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr new file mode 100644 index 0000000000000..04e96f29230fb --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[foreign]-for-foreign.rs:12:1 + | +LL | impl Remote1 for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs b/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs new file mode 100644 index 0000000000000..33e85c164763e --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local { +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign[t],local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[foreign[t],local]-for-foreign.rs new file mode 100644 index 0000000000000..54d4bf04a583c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign[t],local]-for-foreign.rs @@ -0,0 +1,14 @@ +#![feature(re_rebalance_coherence)] + +// check-pass +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +impl Remote2, Local> for usize { } + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs new file mode 100644 index 0000000000000..66a4d9d273469 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote1 for &'a T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..2467097b1a8b3 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-fundamental[t].rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-fundamental[t].rs:16:1 + | +LL | impl<'a, T> Remote1 for &'a T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs new file mode 100644 index 0000000000000..0a67ebcbba44c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr new file mode 100644 index 0000000000000..5c28406f113fc --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t],local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t],local]-for-foreign.rs new file mode 100644 index 0000000000000..24e0f309c4555 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t],local]-for-foreign.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote2, Local> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote2<&'a T, Local> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t],local]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t],local]-for-foreign.stderr new file mode 100644 index 0000000000000..da670bcfc3fc9 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t],local]-for-foreign.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t],local]-for-foreign.rs:12:1 + | +LL | impl Remote2, Local> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t],local]-for-foreign.rs:16:1 + | +LL | impl<'a, T> Remote2<&'a T, Local> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs new file mode 100644 index 0000000000000..71598dae96ab3 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote1<&'a T> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr new file mode 100644 index 0000000000000..dd9702650795e --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-foreign.rs:12:1 + | +LL | impl Remote1> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-foreign.rs:16:1 + | +LL | impl<'a, T> Remote1<&'a T> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs new file mode 100644 index 0000000000000..7bf0306f29ba4 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl<'a, T> Remote1> for &'a T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} +impl<'a, T> Remote1<&'a T> for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..eec57fccea762 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs:12:1 + | +LL | impl<'a, T> Remote1> for &'a T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs:15:1 + | +LL | impl<'a, T> Remote1<&'a T> for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs new file mode 100644 index 0000000000000..54d577c749248 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for Local {} + +impl<'a, T> Remote1<&'a T> for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs new file mode 100644 index 0000000000000..7af929006ef7f --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} +impl<'a, T> Remote1<&'a T> for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr new file mode 100644 index 0000000000000..e017c3ffe6c05 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-t.rs:12:1 + | +LL | impl Remote1> for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-t.rs:15:1 + | +LL | impl<'a, T> Remote1<&'a T> for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local, fundamental[t]]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[local, fundamental[t]]-for-foreign.rs new file mode 100644 index 0000000000000..be0875d0110fd --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local, fundamental[t]]-for-foreign.rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local2(Rc); + +impl Remote2> for u32 {} +impl<'a, T> Remote2 for u32 {} +impl Remote2, Box> for u32 {} +impl<'a, T> Remote2, &'a T> for u32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs new file mode 100644 index 0000000000000..81cf3c3f6eca9 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Rc {} +impl Remote1 for Vec> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs new file mode 100644 index 0000000000000..54425b6d708aa --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl Remote1 for &T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..7859665a7bb58 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-fundamental[t].rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-fundamental[t].rs:16:1 + | +LL | impl Remote1 for &T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs new file mode 100644 index 0000000000000..6b1d93cd94442 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs new file mode 100644 index 0000000000000..6f35c6c9dbc88 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr new file mode 100644 index 0000000000000..be7de8cccb467 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs new file mode 100644 index 0000000000000..5e89c2077330a --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr new file mode 100644 index 0000000000000..5544729b5d640 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-foreign.rs:12:1 + | +LL | impl Remote1 for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs new file mode 100644 index 0000000000000..300a2c4d48a9c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, A, B> Remote1 for &'a B { + //~^ ERROR type parameter `B` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr new file mode 100644 index 0000000000000..be8cc29a6e5b0 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-fundamental.rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `B` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-fundamental.rs:16:1 + | +LL | impl<'a, A, B> Remote1 for &'a B { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `B` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs new file mode 100644 index 0000000000000..769147ea7eabd --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs new file mode 100644 index 0000000000000..c8513380ff73e --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr new file mode 100644 index 0000000000000..de857afd20b15 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/re-rebalance-coherence-rpass.rs b/src/test/ui/coherence/re-rebalance-coherence-rpass.rs deleted file mode 100644 index bacd3b89fad29..0000000000000 --- a/src/test/ui/coherence/re-rebalance-coherence-rpass.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![allow(dead_code)] -#![feature(re_rebalance_coherence)] - -// run-pass -// aux-build:re_rebalance_coherence_lib.rs - -extern crate re_rebalance_coherence_lib as lib; -use lib::*; - -struct Oracle; -impl Backend for Oracle {} -impl<'a, T:'a, Tab> QueryFragment for BatchInsert<'a, T, Tab> {} - -fn main() {} diff --git a/src/test/ui/lint/redundant-semicolon/auxiliary/redundant-semi-proc-macro-def.rs b/src/test/ui/lint/redundant-semicolon/auxiliary/redundant-semi-proc-macro-def.rs new file mode 100644 index 0000000000000..ca741393aec0c --- /dev/null +++ b/src/test/ui/lint/redundant-semicolon/auxiliary/redundant-semi-proc-macro-def.rs @@ -0,0 +1,11 @@ +// no-prefer-dynamic +#![crate_type="proc-macro"] +#![crate_name="redundant_semi_proc_macro"] +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn should_preserve_spans(_attr: TokenStream, item: TokenStream) -> TokenStream { + eprintln!("{:?}", item); + item +} diff --git a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs new file mode 100644 index 0000000000000..f207b235735fe --- /dev/null +++ b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs @@ -0,0 +1,19 @@ +// aux-build:redundant-semi-proc-macro-def.rs + +#![deny(redundant_semicolon)] +extern crate redundant_semi_proc_macro; +use redundant_semi_proc_macro::should_preserve_spans; + +#[should_preserve_spans] +fn span_preservation() { + let tst = 123;; //~ ERROR unnecessary trailing semicolon + match tst { + // Redundant semicolons are parsed as empty tuple exprs + // for the lint, so ensure the lint doesn't affect + // empty tuple exprs explicitly in source. + 123 => (), + _ => () + };;; //~ ERROR unnecessary trailing semicolons +} + +fn main() {} diff --git a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr new file mode 100644 index 0000000000000..5f289c0914d6e --- /dev/null +++ b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr @@ -0,0 +1,21 @@ +TokenStream [Ident { ident: "fn", span: #0 bytes(197..199) }, Ident { ident: "span_preservation", span: #0 bytes(200..217) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(217..219) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(227..230) }, Ident { ident: "tst", span: #0 bytes(231..234) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(235..236) }, Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(237), hi: BytePos(240), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(240..241) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(241..242) }, Ident { ident: "match", span: #0 bytes(288..293) }, Ident { ident: "tst", span: #0 bytes(294..297) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(482), hi: BytePos(485), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(486..488) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(486..488) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(489..491) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(491..492) }, Ident { ident: "_", span: #0 bytes(501..502) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(503..505) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(503..505) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(506..508) }], span: #0 bytes(298..514) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(514..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(516..517) }], span: #0 bytes(221..561) }] +error: unnecessary trailing semicolon + --> $DIR/redundant-semi-proc-macro.rs:9:19 + | +LL | let tst = 123;; + | ^ help: remove this semicolon + | +note: lint level defined here + --> $DIR/redundant-semi-proc-macro.rs:3:9 + | +LL | #![deny(redundant_semicolon)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unnecessary trailing semicolons + --> $DIR/redundant-semi-proc-macro.rs:16:7 + | +LL | };;; + | ^^ help: remove these semicolons + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/test-panic-abort-disabled.rs b/src/test/ui/test-panic-abort-disabled.rs new file mode 100644 index 0000000000000..ea979258a556e --- /dev/null +++ b/src/test/ui/test-panic-abort-disabled.rs @@ -0,0 +1,21 @@ +// no-prefer-dynamic +// compile-flags: --test -Cpanic=abort +// run-flags: --test-threads=1 +// run-fail +// check-run-results + +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support + +#![cfg(test)] + +#[test] +fn it_works() { + assert_eq!(1 + 1, 2); +} + +#[test] +#[should_panic] +fn it_panics() { + assert_eq!(1 + 1, 4); +} diff --git a/src/test/ui/test-panic-abort-disabled.run.stdout b/src/test/ui/test-panic-abort-disabled.run.stdout new file mode 100644 index 0000000000000..171fd2edcf63e --- /dev/null +++ b/src/test/ui/test-panic-abort-disabled.run.stdout @@ -0,0 +1,3 @@ + +running 2 tests +test it_panics ... \ No newline at end of file diff --git a/src/test/ui/test-panic-abort.rs b/src/test/ui/test-panic-abort.rs new file mode 100644 index 0000000000000..9fe54ab737357 --- /dev/null +++ b/src/test/ui/test-panic-abort.rs @@ -0,0 +1,42 @@ +// no-prefer-dynamic +// compile-flags: --test -Cpanic=abort -Zpanic_abort_tests +// run-flags: --test-threads=1 +// run-fail +// check-run-results + +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support + +#![cfg(test)] + +use std::io::Write; + +#[test] +fn it_works() { + assert_eq!(1 + 1, 2); +} + +#[test] +#[should_panic] +fn it_panics() { + assert_eq!(1 + 1, 4); +} + +#[test] +fn it_fails() { + println!("hello, world"); + writeln!(std::io::stdout(), "testing123").unwrap(); + writeln!(std::io::stderr(), "testing321").unwrap(); + assert_eq!(1 + 1, 5); +} + +#[test] +fn it_exits() { + std::process::exit(123); +} + +#[test] +fn it_segfaults() { + let x = unsafe { *(0 as *const u64) }; + println!("output: {}", x); +} diff --git a/src/test/ui/test-panic-abort.run.stdout b/src/test/ui/test-panic-abort.run.stdout new file mode 100644 index 0000000000000..0e21b44c6669e --- /dev/null +++ b/src/test/ui/test-panic-abort.run.stdout @@ -0,0 +1,30 @@ + +running 5 tests +test it_exits ... FAILED +test it_fails ... FAILED +test it_panics ... ok +test it_segfaults ... ok +test it_works ... ok + +failures: + +---- it_exits stdout ---- +---- it_exits stderr ---- +note: got unexpected return code 123 +---- it_fails stdout ---- +hello, world +testing123 +---- it_fails stderr ---- +testing321 +thread 'main' panicked at 'assertion failed: `(left == right)` + left: `2`, + right: `5`', $DIR/test-panic-abort.rs:27:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. + + +failures: + it_exits + it_fails + +test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index edb9eb7d860e2..2358a065d62d1 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -100,6 +100,7 @@ pub enum PassMode { Check, Build, Run, + RunFail, } impl FromStr for PassMode { @@ -120,6 +121,7 @@ impl fmt::Display for PassMode { PassMode::Check => "check", PassMode::Build => "build", PassMode::Run => "run", + PassMode::RunFail => "run-fail", }; fmt::Display::fmt(s, f) } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 48dd68d0f61ee..df56448dd225d 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -610,6 +610,11 @@ impl TestProps { panic!("`run-pass` header is only supported in UI tests") } Some(PassMode::Run) + } else if config.parse_name_directive(ln, "run-fail") { + if config.mode != Mode::Ui { + panic!("`run-fail` header is only supported in UI tests") + } + Some(PassMode::RunFail) } else { None }; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index baed27dd15152..ea31f37c7a52b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -326,6 +326,14 @@ impl<'test> TestCx<'test> { self.props.pass_mode(self.config) } + fn should_run(&self) -> bool { + let pass_mode = self.pass_mode(); + match self.config.mode { + Ui => pass_mode == Some(PassMode::Run) || pass_mode == Some(PassMode::RunFail), + mode => panic!("unimplemented for mode {:?}", mode), + } + } + fn should_run_successfully(&self) -> bool { let pass_mode = self.pass_mode(); match self.config.mode { @@ -1534,7 +1542,7 @@ impl<'test> TestCx<'test> { fn compile_test(&self) -> ProcRes { // Only use `make_exe_name` when the test ends up being executed. let will_execute = match self.config.mode { - Ui => self.should_run_successfully(), + Ui => self.should_run(), Incremental => self.revision.unwrap().starts_with("r"), RunFail | RunPassValgrind | MirOpt | DebugInfoCdb | DebugInfoGdbLldb | DebugInfoGdb | DebugInfoLldb => true, @@ -3107,7 +3115,7 @@ impl<'test> TestCx<'test> { let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - if self.should_run_successfully() { + if self.should_run() { let proc_res = self.exec_compiled_test(); let run_output_errors = if self.props.check_run_results { self.load_compare_outputs(&proc_res, TestOutput::Run, explicit) @@ -3120,8 +3128,14 @@ impl<'test> TestCx<'test> { &proc_res, ); } - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); + if self.should_run_successfully() { + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + } else { + if proc_res.status.success() { + self.fatal_proc_rec("test run succeeded!", &proc_res); + } } }