diff --git a/Cargo.lock b/Cargo.lock index 6beefb3870feb..a130f49b0bec5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -895,6 +895,7 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ + "build_helper", "colored", "diff", "getopts", diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index d3cd085cfb668..66ec8f5f57d21 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -203,7 +203,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } } - self.src_archives.push((archive_path.to_owned(), archive_map)); + self.src_archives.push((archive_path, archive_map)); Ok(()) } diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index de26fd61e4d60..22924efa94842 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -92,7 +92,7 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { let fmt_layer = tracing_subscriber::fmt::layer() .with_writer(io::stderr) .without_time() - .event_format(BacktraceFormatter { backtrace_target: str.to_string() }); + .event_format(BacktraceFormatter { backtrace_target: str }); let subscriber = subscriber.with(fmt_layer); tracing::subscriber::set_global_default(subscriber).unwrap(); } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 088a87ca57104..34a4fd02ea691 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -847,9 +847,7 @@ impl<'a> Parser<'a> { 0, ParseError { description: "expected format parameter to occur after `:`".to_owned(), - note: Some( - format!("`?` comes after `:`, try `{}:{}` instead", word, "?").to_owned(), - ), + note: Some(format!("`?` comes after `:`, try `{}:{}` instead", word, "?")), label: "expected `?` to occur after `:`".to_owned(), span: pos.to(pos), secondary_label: None, diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 45f238ef4bf1f..013d1ab525b0c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -784,6 +784,8 @@ def build_bootstrap(self, color, verbose_count): if self.get_toml("metrics", "build"): args.append("--features") args.append("build-metrics") + if self.json_output: + args.append("--message-format=json") if color == "always": args.append("--color=always") elif color == "never": @@ -841,6 +843,7 @@ def parse_args(): parser.add_argument('--build') parser.add_argument('--color', choices=['always', 'never', 'auto']) parser.add_argument('--clean', action='store_true') + parser.add_argument('--json-output', action='store_true') parser.add_argument('-v', '--verbose', action='count', default=0) return parser.parse_known_args(sys.argv)[0] @@ -852,6 +855,7 @@ def bootstrap(args): build.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) build.verbose = args.verbose != 0 build.clean = args.clean + build.json_output = args.json_output # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, # then `config.toml` in the root directory. diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index d5fcd107502e3..3574f11189ee9 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -557,6 +557,7 @@ mod dist { rustfix_coverage: false, pass: None, run: None, + only_modified: false, }; let build = Build::new(config); @@ -627,6 +628,7 @@ mod dist { rustfix_coverage: false, pass: None, run: None, + only_modified: false, }; // Make sure rustfmt binary not being found isn't an error. config.channel = "beta".to_string(); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 52c3dc0bf7591..ff927ed561b2f 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -124,6 +124,7 @@ pub enum Subcommand { fail_fast: bool, doc_tests: DocTests, rustfix_coverage: bool, + only_modified: bool, }, Bench { paths: Vec, @@ -301,6 +302,7 @@ To learn more about a subcommand, run `./x.py -h`", opts.optflag("", "doc", "only run doc tests"); opts.optflag("", "bless", "update all stderr/stdout files of failing ui tests"); opts.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged"); + opts.optflag("", "only-modified", "only run tests that result has been changed"); opts.optopt( "", "compare-mode", @@ -598,6 +600,7 @@ Arguments: rustc_args: matches.opt_strs("rustc-args"), fail_fast: !matches.opt_present("no-fail-fast"), rustfix_coverage: matches.opt_present("rustfix-coverage"), + only_modified: matches.opt_present("only-modified"), doc_tests: if matches.opt_present("doc") { DocTests::Only } else if matches.opt_present("no-doc") { @@ -777,6 +780,13 @@ impl Subcommand { } } + pub fn only_modified(&self) -> bool { + match *self { + Subcommand::Test { only_modified, .. } => only_modified, + _ => false, + } + } + pub fn force_rerun(&self) -> bool { match *self { Subcommand::Test { force_rerun, .. } => force_rerun, diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index bfc57a85cdb42..6c9c26faef6aa 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -1,8 +1,8 @@ //! Runs rustfmt on the repository. use crate::builder::Builder; -use crate::util::{output, output_result, program_out_of_date, t}; -use build_helper::git::updated_master_branch; +use crate::util::{output, program_out_of_date, t}; +use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; use std::collections::VecDeque; use std::path::{Path, PathBuf}; @@ -80,23 +80,11 @@ fn update_rustfmt_version(build: &Builder<'_>) { /// /// Returns `None` if all files should be formatted. fn get_modified_rs_files(build: &Builder<'_>) -> Result>, String> { - let Ok(updated_master) = updated_master_branch(Some(&build.config.src)) else { return Ok(None); }; - if !verify_rustfmt_version(build) { return Ok(None); } - let merge_base = - output_result(build.config.git().arg("merge-base").arg(&updated_master).arg("HEAD"))?; - Ok(Some( - output_result( - build.config.git().arg("diff-index").arg("--name-only").arg(merge_base.trim()), - )? - .lines() - .map(|s| s.trim().to_owned()) - .filter(|f| Path::new(f).extension().map_or(false, |ext| ext == "rs")) - .collect(), - )) + get_git_modified_files(Some(&build.config.src), &vec!["rs"]) } #[derive(serde::Deserialize)] diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 8a0c532cfb02f..f8835fe11a8cc 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1510,6 +1510,10 @@ note: if you're sure you want to do this, please open an issue as to why. In the if builder.config.rust_optimize_tests { cmd.arg("--optimize-tests"); } + if builder.config.cmd.only_modified() { + cmd.arg("--only-modified"); + } + let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests)); flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string())); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d497f7ea67976..42bdbddbce617 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2209,10 +2209,12 @@ fn clean_maybe_renamed_item<'tcx>( }; let mut extra_attrs = Vec::new(); - if let Some(hir::Node::Item(use_node)) = - import_id.and_then(|def_id| cx.tcx.hir().find_by_def_id(def_id)) + if let Some(import_id) = import_id && + let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id) { - // We get all the various imports' attributes. + // First, we add the attributes from the current import. + extra_attrs.extend_from_slice(inline::load_attrs(cx, import_id.to_def_id())); + // Then we get all the various imports' attributes. get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index dee0a01a65413..8f401a2fc1d5b 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -740,11 +740,7 @@ pub(crate) fn find_testable_code( } Event::Text(ref s) if register_header.is_some() => { let level = register_header.unwrap(); - if s.is_empty() { - tests.register_header("", level); - } else { - tests.register_header(s, level); - } + tests.register_header(s, level); register_header = None; } _ => {} diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 82a51a8467bcd..d0f497321abf5 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1081,10 +1081,10 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); - write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx)); write!( w, - "type {}{}{where_clause} = {type_};", + "{}type {}{}{where_clause} = {type_};", + visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), it.name.unwrap(), t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), @@ -1138,13 +1138,11 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: §\ {name}: {ty}\ ", - id = id, - name = name, shortty = ItemType::StructField, ty = ty.print(cx), ); if let Some(stability_class) = field.stability_class(cx.tcx()) { - write!(w, "", stab = stability_class); + write!(w, ""); } document(w, cx, field, Some(it), HeadingOffset::H3); } @@ -1242,7 +1240,6 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w, "
\ §", - id = id, ); render_stability_since_raw_with_extra( w, @@ -1280,8 +1277,11 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: if let Some((heading, fields)) = heading_and_fields { let variant_id = cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); - write!(w, "
", id = variant_id); - write!(w, "

{heading}

", heading = heading); + write!( + w, + "
\ +

{heading}

", + ); document_non_exhaustive(w, variant); for field in fields { match *field.kind { @@ -1299,7 +1299,6 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: §\ {f}: {t}\ ", - id = id, f = field.name.unwrap(), t = ty.print(cx) ); @@ -1450,11 +1449,9 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean w, "\ §\ - {name}: {ty}\ + {field_name}: {ty}\ ", item_type = ItemType::StructField, - id = id, - name = field_name, ty = ty.print(cx) ); document(w, cx, field, Some(it), HeadingOffset::H3); @@ -1840,8 +1837,8 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { if layout.abi.is_unsized() { write!(w, "(unsized)"); } else { - let bytes = layout.size.bytes() - tag_size; - write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },); + let size = layout.size.bytes() - tag_size; + write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" },); } } @@ -1896,7 +1893,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { for (index, layout) in variants.iter_enumerated() { let name = adt.variant(index).name; - write!(w, "
  • {name}: ", name = name); + write!(w, "
  • {name}: "); write_size_of_layout(w, layout, tag_size); writeln!(w, "
  • "); } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 692adcf0a8091..62e190b4bd8ed 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -297,7 +297,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { match ty_res { Res::Def(DefKind::Enum, did) => match tcx.type_of(did).kind() { ty::Adt(def, _) if def.is_enum() => { - if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name) { + if let Some(variant) = def.variants().iter().find(|v| v.name == variant_name) + && let Some(field) = variant.fields.iter().find(|f| f.name == variant_field_name) { Ok((ty_res, field.did)) } else { Err(UnresolvedPath { @@ -1716,15 +1717,35 @@ fn resolution_failure( // Otherwise, it must be an associated item or variant let res = partial_res.expect("None case was handled by `last_found_module`"); - let kind = match res { - Res::Def(kind, _) => Some(kind), + let kind_did = match res { + Res::Def(kind, did) => Some((kind, did)), Res::Primitive(_) => None, }; - let path_description = if let Some(kind) = kind { + let is_struct_variant = |did| { + if let ty::Adt(def, _) = tcx.type_of(did).kind() + && def.is_enum() + && let Some(variant) = def.variants().iter().find(|v| v.name == res.name(tcx)) { + // ctor is `None` if variant is a struct + variant.ctor.is_none() + } else { + false + } + }; + let path_description = if let Some((kind, did)) = kind_did { match kind { Mod | ForeignMod => "inner item", Struct => "field or associated item", Enum | Union => "variant or associated item", + Variant if is_struct_variant(did) => { + let variant = res.name(tcx); + let note = format!("variant `{variant}` has no such field"); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + return; + } Variant | Field | Closure diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 088cb3f339492..9c1e5f4a3cddb 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -378,7 +378,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let nonexported = !tcx.has_attr(def_id, sym::macro_export); if is_macro_2_0 || nonexported || self.inlining { - self.add_to_current_mod(item, renamed, None); + self.add_to_current_mod(item, renamed, import_id); } } hir::ItemKind::Mod(ref m) => { diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index dc62051cb85da..168633c8f6334 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -1,5 +1,24 @@ +use std::process::Stdio; use std::{path::Path, process::Command}; +/// Runs a command and returns the output +fn output_result(cmd: &mut Command) -> Result { + let output = match cmd.stderr(Stdio::inherit()).output() { + Ok(status) => status, + Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)), + }; + if !output.status.success() { + return Err(format!( + "command did not execute successfully: {:?}\n\ + expected success, got: {}\n{}", + cmd, + output.status, + String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? + )); + } + Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?) +} + /// Finds the remote for rust-lang/rust. /// For example for these remotes it will return `upstream`. /// ```text @@ -14,13 +33,7 @@ pub fn get_rust_lang_rust_remote(git_dir: Option<&Path>) -> Result) -> Result { // We could implement smarter logic here in the future. Ok("origin/master".into()) } + +/// Returns the files that have been modified in the current branch compared to the master branch. +/// The `extensions` parameter can be used to filter the files by their extension. +/// If `extensions` is empty, all files will be returned. +pub fn get_git_modified_files( + git_dir: Option<&Path>, + extensions: &Vec<&str>, +) -> Result>, String> { + let Ok(updated_master) = updated_master_branch(git_dir) else { return Ok(None); }; + + let git = || { + let mut git = Command::new("git"); + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + git + }; + + let merge_base = output_result(git().arg("merge-base").arg(&updated_master).arg("HEAD"))?; + let files = output_result(git().arg("diff-index").arg("--name-only").arg(merge_base.trim()))? + .lines() + .map(|s| s.trim().to_owned()) + .filter(|f| { + Path::new(f).extension().map_or(false, |ext| { + extensions.is_empty() || extensions.contains(&ext.to_str().unwrap()) + }) + }) + .collect(); + Ok(Some(files)) +} + +/// Returns the files that haven't been added to git yet. +pub fn get_git_untracked_files(git_dir: Option<&Path>) -> Result>, String> { + let Ok(_updated_master) = updated_master_branch(git_dir) else { return Ok(None); }; + let mut git = Command::new("git"); + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + + let files = output_result(git.arg("ls-files").arg("--others").arg("--exclude-standard"))? + .lines() + .map(|s| s.trim().to_owned()) + .collect(); + Ok(Some(files)) +} diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 1911f0f9c941c..deed6fbd4391f 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -9,6 +9,7 @@ diff = "0.1.10" unified-diff = "0.2.1" getopts = "0.2" miropt-test-tools = { path = "../miropt-test-tools" } +build_helper = { path = "../build_helper" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } regex = "1.0" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 3676f69b100db..7fe2e6257d9e7 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -380,6 +380,9 @@ pub struct Config { /// Whether to rerun tests even if the inputs are unchanged. pub force_rerun: bool, + /// Only rerun the tests that result has been modified accoring to Git status + pub only_modified: bool, + pub target_cfg: LazyCell, } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 3092c656cd729..c648b2f12f101 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -8,15 +8,17 @@ extern crate test; use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths}; use crate::util::logv; +use build_helper::git::{get_git_modified_files, get_git_untracked_files}; +use core::panic; use getopts::Options; use lazycell::LazyCell; -use std::env; use std::ffi::OsString; use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::time::SystemTime; +use std::{env, vec}; use test::ColorConfig; use tracing::*; use walkdir::WalkDir; @@ -145,9 +147,10 @@ pub fn parse_config(args: Vec) -> Config { "", "rustfix-coverage", "enable this to generate a Rustfix coverage file, which is saved in \ - `.//rustfix_missing_coverage.txt`", + `.//rustfix_missing_coverage.txt`", ) .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") + .optflag("", "only-modified", "only run tests that result been modified") .optflag("h", "help", "show this message") .reqopt("", "channel", "current Rust channel", "CHANNEL") .optopt("", "edition", "default Rust edition", "EDITION"); @@ -279,6 +282,7 @@ pub fn parse_config(args: Vec) -> Config { lldb_python_dir: matches.opt_str("lldb-python-dir"), verbose: matches.opt_present("verbose"), quiet: matches.opt_present("quiet"), + only_modified: matches.opt_present("only-modified"), color, remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse), @@ -521,8 +525,18 @@ pub fn test_opts(config: &Config) -> test::TestOpts { pub fn make_tests(config: &Config, tests: &mut Vec) { debug!("making tests from {:?}", config.src_base.display()); let inputs = common_inputs_stamp(config); - collect_tests_from_dir(config, &config.src_base, &PathBuf::new(), &inputs, tests) - .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); + let modified_tests = modified_tests(config, &config.src_base).unwrap_or_else(|err| { + panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err) + }); + collect_tests_from_dir( + config, + &config.src_base, + &PathBuf::new(), + &inputs, + tests, + &modified_tests, + ) + .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); } /// Returns a stamp constructed from input files common to all test cases. @@ -561,12 +575,35 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp } +fn modified_tests(config: &Config, dir: &Path) -> Result, String> { + if !config.only_modified { + return Ok(vec![]); + } + let files = + get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]); + // Add new test cases to the list, it will be convenient in daily development. + let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]); + + let all_paths = [&files[..], &untracked_files[..]].concat(); + let full_paths = { + let mut full_paths: Vec = all_paths + .into_iter() + .map(|f| fs::canonicalize(&f).unwrap().with_extension("").with_extension("rs")) + .collect(); + full_paths.dedup(); + full_paths.sort_unstable(); + full_paths + }; + Ok(full_paths) +} + fn collect_tests_from_dir( config: &Config, dir: &Path, relative_dir_path: &Path, inputs: &Stamp, tests: &mut Vec, + modified_tests: &Vec, ) -> io::Result<()> { // Ignore directories that contain a file named `compiletest-ignore-dir`. if dir.join("compiletest-ignore-dir").exists() { @@ -597,7 +634,7 @@ fn collect_tests_from_dir( let file = file?; let file_path = file.path(); let file_name = file.file_name(); - if is_test(&file_name) { + if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) { debug!("found test file: {:?}", file_path.display()); let paths = TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; @@ -607,7 +644,14 @@ fn collect_tests_from_dir( let relative_file_path = relative_dir_path.join(file.file_name()); if &file_name != "auxiliary" { debug!("found directory: {:?}", file_path.display()); - collect_tests_from_dir(config, &file_path, &relative_file_path, inputs, tests)?; + collect_tests_from_dir( + config, + &file_path, + &relative_file_path, + inputs, + tests, + modified_tests, + )?; } } else { debug!("found other file/directory: {:?}", file_path.display()); diff --git a/tests/rustdoc-ui/intra-doc/errors.rs b/tests/rustdoc-ui/intra-doc/errors.rs index b29f7c29b5d86..95dd2b98e037e 100644 --- a/tests/rustdoc-ui/intra-doc/errors.rs +++ b/tests/rustdoc-ui/intra-doc/errors.rs @@ -103,3 +103,19 @@ pub trait T { macro_rules! m { () => {}; } + +///[`TestEnum::Variant1::field_name`] +//~^ ERROR unresolved link +//~| NOTE variant `Variant1` has no such field +pub enum TestEnum { + Variant1 {}, + Variant2 { field_name: u64 }, +} + +///[`TestEnumNoFields::Variant1::field_name`] +//~^ ERROR unresolved link +//~| NOTE `Variant1` is a variant, not a module or type, and cannot have associated items +pub enum TestEnumNoFields { + Variant1 (), + Variant2 {}, +} diff --git a/tests/rustdoc-ui/intra-doc/errors.stderr b/tests/rustdoc-ui/intra-doc/errors.stderr index 9a1896fb0cd63..1b2416d7da765 100644 --- a/tests/rustdoc-ui/intra-doc/errors.stderr +++ b/tests/rustdoc-ui/intra-doc/errors.stderr @@ -142,6 +142,18 @@ error: unresolved link to `T::h` LL | /// [T::h!] | ^^^^^ the trait `T` has no macro named `h` +error: unresolved link to `TestEnum::Variant1::field_name` + --> $DIR/errors.rs:107:6 + | +LL | ///[`TestEnum::Variant1::field_name`] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant `Variant1` has no such field + +error: unresolved link to `TestEnumNoFields::Variant1::field_name` + --> $DIR/errors.rs:115:6 + | +LL | ///[`TestEnumNoFields::Variant1::field_name`] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Variant1` is a variant, not a module or type, and cannot have associated items + error: unresolved link to `m` --> $DIR/errors.rs:98:6 | @@ -153,5 +165,5 @@ help: to link to the macro, add an exclamation mark LL | /// [m!()] | + -error: aborting due to 20 previous errors +error: aborting due to 22 previous errors diff --git a/tests/rustdoc/reexport-macro.rs b/tests/rustdoc/reexport-macro.rs new file mode 100644 index 0000000000000..c4dec703aed3b --- /dev/null +++ b/tests/rustdoc/reexport-macro.rs @@ -0,0 +1,23 @@ +// Ensure that macros are correctly reexported and that they get both the comment from the +// `pub use` and from the macro. + +#![crate_name = "foo"] + +// @has 'foo/macro.foo.html' +// @!has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'x y' +// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'y' +#[macro_use] +mod my_module { + /// y + #[macro_export] + macro_rules! foo { + () => (); + } +} + +// @has 'foo/another_mod/macro.bar.html' +// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'x y' +pub mod another_mod { + /// x + pub use crate::foo as bar; +}