diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index cb1cb3c74dbb5..e32dae49131ab 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -221,9 +221,7 @@ impl CodegenBackend for CraneliftCodegenBackend { sess, &codegen_results, outputs, - ); - - Ok(()) + ) } } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 26fd1cfbcd08e..aa4db1622b233 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -292,9 +292,7 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary::<LlvmArchiveBuilder<'_>>(sess, &codegen_results, outputs); - - Ok(()) + link_binary::<LlvmArchiveBuilder<'_>>(sess, &codegen_results, outputs) } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f9efa448c93fa..773a1c500b2f6 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,9 +1,9 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::Handler; +use rustc_errors::{ErrorReported, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{DllCallingConvention, DllImport}; +use rustc_middle::middle::cstore::DllImport; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; @@ -35,7 +35,6 @@ use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, Se use tempfile::Builder as TempFileBuilder; use std::ffi::OsString; -use std::iter::FromIterator; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{ascii, char, env, fmt, fs, io, mem, str}; @@ -54,7 +53,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, outputs: &OutputFilenames, -) { +) -> Result<(), ErrorReported> { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); for &crate_type in sess.crate_types().iter() { @@ -95,11 +94,17 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( match crate_type { CrateType::Rlib => { let _timer = sess.timer("link_rlib"); - link_rlib::<B>(sess, codegen_results, RlibFlavor::Normal, &out_filename, &path) - .build(); + link_rlib::<B>( + sess, + codegen_results, + RlibFlavor::Normal, + &out_filename, + &path, + )? + .build(); } CrateType::Staticlib => { - link_staticlib::<B>(sess, codegen_results, &out_filename, &path); + link_staticlib::<B>(sess, codegen_results, &out_filename, &path)?; } _ => { link_natively::<B>( @@ -145,6 +150,8 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( } } }); + + Ok(()) } pub fn each_linked_rlib( @@ -220,7 +227,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( flavor: RlibFlavor, out_filename: &Path, tmpdir: &MaybeTempDir, -) -> B { +) -> Result<B, ErrorReported> { info!("preparing rlib to {:?}", out_filename); let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None); @@ -259,7 +266,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries) + collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? { ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); } @@ -312,7 +319,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } } - return ab; + return Ok(ab); // For rlibs we "pack" rustc metadata into a dummy object file. When rustc // creates a dylib crate type it will pass `--whole-archive` (or the @@ -454,65 +461,40 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( fn collate_raw_dylibs( sess: &Session, used_libraries: &[NativeLib], -) -> Vec<(String, Vec<DllImport>)> { - let mut dylib_table: FxHashMap<String, FxHashSet<DllImport>> = FxHashMap::default(); +) -> Result<Vec<(String, Vec<DllImport>)>, ErrorReported> { + // Use index maps to preserve original order of imports and libraries. + let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default(); for lib in used_libraries { if lib.kind == NativeLibKind::RawDylib { - let name = lib.name.unwrap_or_else(|| - bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier") - ); - let name = if matches!(lib.verbatim, Some(true)) { - name.to_string() - } else { - format!("{}.dll", name) - }; - dylib_table.entry(name).or_default().extend(lib.dll_imports.iter().cloned()); - } - } - - // Rustc already signals an error if we have two imports with the same name but different - // calling conventions (or function signatures), so we don't have pay attention to those - // when ordering. - // FIXME: when we add support for ordinals, figure out if we need to do anything if we - // have two DllImport values with the same name but different ordinals. - let mut result: Vec<(String, Vec<DllImport>)> = dylib_table - .into_iter() - .map(|(lib_name, import_table)| { - let mut imports = Vec::from_iter(import_table.into_iter()); - imports.sort_unstable_by_key(|x: &DllImport| x.name.as_str()); - (lib_name, imports) - }) - .collect::<Vec<_>>(); - result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| { - a.0.cmp(&b.0) - }); - let result = result; - - // Check for multiple imports with the same name but different calling conventions or - // (when relevant) argument list sizes. Rustc only signals an error for this if the - // declarations are at the same scope level; if one shadows the other, we only get a lint - // warning. - for (library, imports) in &result { - let mut import_table: FxHashMap<Symbol, DllCallingConvention> = FxHashMap::default(); - for import in imports { - if let Some(old_convention) = - import_table.insert(import.name, import.calling_convention) - { - if import.calling_convention != old_convention { - sess.span_fatal( - import.span, - &format!( - "multiple definitions of external function `{}` from library `{}` have different calling conventions", - import.name, - library, - )); + let ext = if matches!(lib.verbatim, Some(true)) { "" } else { ".dll" }; + let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext); + let imports = dylib_table.entry(name.clone()).or_default(); + for import in &lib.dll_imports { + if let Some(old_import) = imports.insert(import.name, import) { + // FIXME: when we add support for ordinals, figure out if we need to do anything + // if we have two DllImport values with the same name but different ordinals. + if import.calling_convention != old_import.calling_convention { + sess.span_err( + import.span, + &format!( + "multiple declarations of external function `{}` from \ + library `{}` have different calling conventions", + import.name, name, + ), + ); + } } } } } - - result + sess.compile_status()?; + Ok(dylib_table + .into_iter() + .map(|(name, imports)| { + (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) + }) + .collect()) } /// Create a static archive. @@ -531,9 +513,9 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( codegen_results: &CodegenResults, out_filename: &Path, tempdir: &MaybeTempDir, -) { +) -> Result<(), ErrorReported> { let mut ab = - link_rlib::<B>(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir); + link_rlib::<B>(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir)?; let mut all_native_libs = vec![]; let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { @@ -581,6 +563,8 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( print_native_static_libs(sess, &all_native_libs); } } + + Ok(()) } fn escape_stdout_stderr_string(s: &[u8]) -> String { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 6877d6ef542c7..a4913a32e81ef 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1581,7 +1581,7 @@ impl EncodeContext<'a, 'tcx> { fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); - self.lazy(used_libraries.iter().cloned()) + self.lazy(used_libraries.iter()) } fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 4c35b49bcefd7..8150e67929509 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -64,7 +64,7 @@ pub enum LinkagePreference { RequireStatic, } -#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +#[derive(Debug, Encodable, Decodable, HashStable)] pub struct NativeLib { pub kind: NativeLibKind, pub name: Option<Symbol>, @@ -75,7 +75,7 @@ pub struct NativeLib { pub dll_imports: Vec<DllImport>, } -#[derive(Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] pub struct DllImport { pub name: Symbol, pub ordinal: Option<u16>, @@ -92,7 +92,7 @@ pub struct DllImport { /// /// The usize value, where present, indicates the size of the function's argument list /// in bytes. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] +#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable)] pub enum DllCallingConvention { C, Stdcall(usize), diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index b0156daf17eff..6b51adc6aafdd 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -281,11 +281,10 @@ pub struct CaptureInfo<'tcx> { } pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { - let name = match place.base { + let mut curr_string: String = match place.base { HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(), _ => bug!("Capture_information should only contain upvars"), }; - let mut curr_string = name; for (i, proj) in place.projections.iter().enumerate() { match proj.kind { @@ -314,7 +313,7 @@ pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> } } - curr_string.to_string() + curr_string } #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)] diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 12d0c14a3d51a..d35868881558e 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -66,6 +66,10 @@ crate fn compare_impl_method<'tcx>( { return; } + + if let Err(ErrorReported) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) { + return; + } } fn compare_predicate_entailment<'tcx>( @@ -929,6 +933,68 @@ fn compare_synthetic_generics<'tcx>( if error_found { Err(ErrorReported) } else { Ok(()) } } +fn compare_const_param_types<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + trait_m: &ty::AssocItem, + trait_item_span: Option<Span>, +) -> Result<(), ErrorReported> { + let const_params_of = |def_id| { + tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind { + GenericParamDefKind::Const { .. } => Some(param.def_id), + _ => None, + }) + }; + let const_params_impl = const_params_of(impl_m.def_id); + let const_params_trait = const_params_of(trait_m.def_id); + + for (const_param_impl, const_param_trait) in iter::zip(const_params_impl, const_params_trait) { + let impl_ty = tcx.type_of(const_param_impl); + let trait_ty = tcx.type_of(const_param_trait); + if impl_ty != trait_ty { + let (impl_span, impl_ident) = match tcx.hir().get_if_local(const_param_impl) { + Some(hir::Node::GenericParam(hir::GenericParam { span, name, .. })) => ( + span, + match name { + hir::ParamName::Plain(ident) => Some(ident), + _ => None, + }, + ), + other => bug!( + "expected GenericParam, found {:?}", + other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n)) + ), + }; + let trait_span = match tcx.hir().get_if_local(const_param_trait) { + Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span), + _ => None, + }; + let mut err = struct_span_err!( + tcx.sess, + *impl_span, + E0053, + "method `{}` has an incompatible const parameter type for trait", + trait_m.ident + ); + err.span_note( + trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span), + &format!( + "the const parameter{} has type `{}`, but the declaration \ + in trait `{}` has type `{}`", + &impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{}`", ident)), + impl_ty, + tcx.def_path_str(trait_m.def_id), + trait_ty + ), + ); + err.emit(); + return Err(ErrorReported); + } + } + + Ok(()) +} + crate fn compare_const_impl<'tcx>( tcx: TyCtxt<'tcx>, impl_c: &ty::AssocItem, diff --git a/library/core/src/option.rs b/library/core/src/option.rs index b7af3ea8c1af4..c27db0767ac9d 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -356,7 +356,7 @@ //! // must have the same concrete type. //! fn make_iter(do_insert: bool) -> impl Iterator<Item = i32> { //! // Explicit returns to illustrate return types not matching -//! match x { +//! match do_insert { //! true => return (0..4).chain(once(42)).chain(4..8), //! false => return (0..4).chain(empty()).chain(4..8), //! } diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 2e4016e24bc3f..c8af369a9695e 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -417,3 +417,10 @@ This flag is **deprecated** and **has no effect**. Rustdoc only supports Rust source code and Markdown input formats. If the file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file. Otherwise, it assumes that the input file is Rust. + +## `--nocapture` + +When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be +captured by rustdoc. Instead, the output will be directed to your terminal, +as if you had run the test executable manually. This is especially useful +for debugging your tests! diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 80aaae1580114..1a2852dc6c724 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -14,7 +14,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::middle::resolve_lifetime as rl; @@ -85,12 +85,6 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> { } } -impl Clean<ExternalCrate> for CrateNum { - fn clean(&self, _cx: &mut DocContext<'_>) -> ExternalCrate { - ExternalCrate { crate_num: *self } - } -} - impl Clean<Item> for doctree::Module<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Item { let mut items: Vec<Item> = vec![]; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 859746b6a2df7..2fd2d14bcabc3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -118,7 +118,7 @@ crate struct Crate { crate name: Symbol, crate src: FileName, crate module: Item, - crate externs: Vec<(CrateNum, ExternalCrate)>, + crate externs: Vec<ExternalCrate>, crate primitives: ThinVec<(DefId, PrimitiveType)>, // These are later on moved into `CACHEKEY`, leaving the map empty. // Only here so that they can be filtered through the rustdoc passes. @@ -133,14 +133,14 @@ crate struct TraitWithExtraInfo { crate is_notable: bool, } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] crate struct ExternalCrate { crate crate_num: CrateNum, } impl ExternalCrate { #[inline] - fn def_id(&self) -> DefId { + crate fn def_id(&self) -> DefId { DefId { krate: self.crate_num, index: CRATE_DEF_INDEX } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index dea016a467d64..bdd5350aab2cb 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,9 +1,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ - inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, - Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, - Visibility, + inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, + ItemKind, Lifetime, Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, + TypeBinding, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -35,11 +35,11 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { let mut externs = Vec::new(); for &cnum in cx.tcx.crates(()).iter() { - externs.push((cnum, cnum.clean(cx))); + externs.push(ExternalCrate { crate_num: cnum }); // Analyze doc-reachability for extern items LibEmbargoVisitor::new(cx).visit_lib(cnum); } - externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + externs.sort_unstable_by_key(|e| e.crate_num); // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. @@ -61,7 +61,7 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { _ => unreachable!(), } - let local_crate = LOCAL_CRATE.clean(cx); + let local_crate = ExternalCrate { crate_num: LOCAL_CRATE }; let src = local_crate.src(cx.tcx); let name = local_crate.name(cx.tcx); let primitives = local_crate.primitives(cx.tcx); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 4cf647a81ae4b..adbdde0d92cd6 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -156,6 +156,8 @@ crate struct Options { crate run_check: bool, /// Whether doctests should emit unused externs crate json_unused_externs: bool, + /// Whether to skip capturing stdout and stderr of tests. + crate nocapture: bool, } impl fmt::Debug for Options { @@ -199,6 +201,7 @@ impl fmt::Debug for Options { .field("enable-per-target-ignores", &self.enable_per_target_ignores) .field("run_check", &self.run_check) .field("no_run", &self.no_run) + .field("nocapture", &self.nocapture) .finish() } } @@ -627,6 +630,7 @@ impl Options { let run_check = matches.opt_present("check"); let generate_redirect_map = matches.opt_present("generate-redirect-map"); let show_type_layout = matches.opt_present("show-type-layout"); + let nocapture = matches.opt_present("nocapture"); let (lint_opts, describe_lints, lint_cap, _) = get_cmd_lint_options(matches, error_format, &debugging_opts); @@ -665,6 +669,7 @@ impl Options { test_builder, run_check, no_run, + nocapture, render_options: RenderOptions { output, external_html, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c5ca396e72029..5ce7c49278d23 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -107,6 +107,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { let mut test_args = options.test_args.clone(); let display_warnings = options.display_warnings; + let nocapture = options.nocapture; let externs = options.externs.clone(); let json_unused_externs = options.json_unused_externs; @@ -166,6 +167,9 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { }; test_args.insert(0, "rustdoctest".to_string()); + if nocapture { + test_args.push("--nocapture".to_string()); + } test::test_main(&test_args, tests, Some(test::Options::new().display_output(display_warnings))); @@ -456,7 +460,16 @@ fn run_test( cmd.current_dir(run_directory); } - match cmd.output() { + let result = if options.nocapture { + cmd.status().map(|status| process::Output { + status, + stdout: Vec::new(), + stderr: Vec::new(), + }) + } else { + cmd.output() + }; + match result { Err(e) => return Err(TestFailure::ExecutionError(e)), Ok(out) => { if should_panic && out.status.success() { diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index e7d6e5ac2c24b..5ea2cdc2ad909 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -151,19 +151,18 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code - for &(n, ref e) in &krate.externs { + for &e in &krate.externs { let name = e.name(tcx); let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u); - let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - self.extern_locations.insert(n, e.location(extern_url, &dst, tcx)); - self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module)); + self.extern_locations.insert(e.crate_num, e.location(extern_url, &dst, tcx)); + self.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module)); } // Cache where all known primitives have their documentation located. // // Favor linking to as local extern as possible, so iterate all crates in // reverse topological order. - for &(_, ref e) in krate.externs.iter().rev() { + for &e in krate.externs.iter().rev() { for &(def_id, prim) in &e.primitives(tcx) { self.primitive_locations.insert(prim, def_id); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d4d87819c0d7a..19deaa11388d8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -604,6 +604,9 @@ fn opts() -> Vec<RustcOptGroup> { unstable("show-type-layout", |o| { o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs") }), + unstable("nocapture", |o| { + o.optflag("", "nocapture", "Don't capture stdout and stderr of tests") + }), ] } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 45966c0058df4..6c8b95c04c9e4 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -136,6 +136,9 @@ crate fn test(mut options: Options) -> Result<(), String> { find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None); options.test_args.insert(0, "rustdoctest".to_string()); + if options.nocapture { + options.test_args.push("--nocapture".to_string()); + } test::test_main( &options.test_args, collector.tests, diff --git a/src/test/rustdoc-ui/nocapture-fail.rs b/src/test/rustdoc-ui/nocapture-fail.rs new file mode 100644 index 0000000000000..f878ea0962c08 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.rs @@ -0,0 +1,11 @@ +// check-pass +// compile-flags:--test -Zunstable-options --nocapture +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ```compile_fail +/// fn foo() { +/// Input: 123 +/// } +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/nocapture-fail.stderr b/src/test/rustdoc-ui/nocapture-fail.stderr new file mode 100644 index 0000000000000..ef03347bab1ef --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.stderr @@ -0,0 +1,18 @@ +error: struct literal body without path + --> $DIR/nocapture-fail.rs:7:10 + | +LL | fn foo() { + | __________^ +LL | | Input: 123 +LL | | } + | |_^ + | +help: you might have forgotten to add the struct literal inside the block + | +LL | fn foo() { SomeStruct { +LL | Input: 123 +LL | } } + | + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/nocapture-fail.stdout b/src/test/rustdoc-ui/nocapture-fail.stdout new file mode 100644 index 0000000000000..131713e3a3f2d --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/nocapture-fail.rs - Foo (line 6) - compile fail ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/nocapture.rs b/src/test/rustdoc-ui/nocapture.rs new file mode 100644 index 0000000000000..321f5ca08eded --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.rs @@ -0,0 +1,10 @@ +// check-pass +// compile-flags:--test -Zunstable-options --nocapture +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// println!("hello!"); +/// eprintln!("stderr"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/nocapture.stderr b/src/test/rustdoc-ui/nocapture.stderr new file mode 100644 index 0000000000000..af6415db3c724 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.stderr @@ -0,0 +1 @@ +stderr diff --git a/src/test/rustdoc-ui/nocapture.stdout b/src/test/rustdoc-ui/nocapture.stdout new file mode 100644 index 0000000000000..4880e75da7062 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.stdout @@ -0,0 +1,7 @@ + +running 1 test +hello! +test $DIR/nocapture.rs - Foo (line 6) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/ui/const-generics/issue-86820.rs b/src/test/ui/const-generics/issue-86820.rs new file mode 100644 index 0000000000000..04650403c6baf --- /dev/null +++ b/src/test/ui/const-generics/issue-86820.rs @@ -0,0 +1,25 @@ +// Regression test for the ICE described in #86820. + +#![allow(unused,dead_code)] +use std::ops::BitAnd; + +const C: fn() = || is_set(); +fn is_set() { + 0xffu8.bit::<0>(); +} + +trait Bits { + fn bit<const I : u8>(self) -> bool; + //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8` +} + +impl Bits for u8 { + fn bit<const I : usize>(self) -> bool { + //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053] + let i = 1 << I; + let mask = u8::from(i); + mask & self == mask + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issue-86820.stderr b/src/test/ui/const-generics/issue-86820.stderr new file mode 100644 index 0000000000000..f4396f2f2b0a2 --- /dev/null +++ b/src/test/ui/const-generics/issue-86820.stderr @@ -0,0 +1,15 @@ +error[E0053]: method `bit` has an incompatible const parameter type for trait + --> $DIR/issue-86820.rs:17:18 + | +LL | fn bit<const I : usize>(self) -> bool { + | ^ + | +note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8` + --> $DIR/issue-86820.rs:12:18 + | +LL | fn bit<const I : u8>(self) -> bool; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs new file mode 100644 index 0000000000000..d02bebc9d61d2 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs @@ -0,0 +1,19 @@ +// only-i686-pc-windows-msvc +// compile-flags: --crate-type lib --emit link +#![allow(clashing_extern_declarations)] +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + fn f(x: i32); +} + +pub fn lib_main() { + #[link(name = "foo", kind = "raw-dylib")] + extern "stdcall" { + fn f(x: i32); + //~^ ERROR multiple declarations of external function `f` from library `foo.dll` have different calling conventions + } + + unsafe { f(42); } +} diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr new file mode 100644 index 0000000000000..a9cfd6b23f9f8 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multiple-declarations.rs:4:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information + +error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions + --> $DIR/multiple-declarations.rs:14:9 + | +LL | fn f(x: i32); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.rs b/src/test/ui/type-alias-impl-trait/issue-63355.rs new file mode 100644 index 0000000000000..8762d189c7389 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63355.rs @@ -0,0 +1,50 @@ +#![feature(min_type_alias_impl_trait)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +pub trait Foo {} + +pub trait Bar { + type Foo: Foo; + + fn foo() -> Self::Foo; +} + +pub trait Baz { + type Foo: Foo; + type Bar: Bar<Foo = Self::Foo>; + + fn foo() -> Self::Foo; + fn bar() -> Self::Bar; +} + +impl Foo for () {} + +impl Bar for () { + type Foo = FooImpl; + + fn foo() -> Self::Foo { + () + } +} + +// FIXME(#86731): The below is illegal use of `min_type_alias_impl_trait` +// but the compiler doesn't report it, we should fix it. +pub type FooImpl = impl Foo; +pub type BarImpl = impl Bar<Foo = FooImpl>; +//~^ ERROR: type mismatch resolving `<() as Bar>::Foo == ()` + +impl Baz for () { + type Foo = FooImpl; + type Bar = BarImpl; + + fn foo() -> Self::Foo { + () + } + + fn bar() -> Self::Bar { + () + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.stderr b/src/test/ui/type-alias-impl-trait/issue-63355.stderr new file mode 100644 index 0000000000000..dc5370a2666b7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63355.stderr @@ -0,0 +1,14 @@ +error[E0271]: type mismatch resolving `<() as Bar>::Foo == ()` + --> $DIR/issue-63355.rs:34:20 + | +LL | pub type FooImpl = impl Foo; + | -------- the found opaque type +LL | pub type BarImpl = impl Bar<Foo = FooImpl>; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type + | + = note: expected unit type `()` + found opaque type `impl Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`.