From 2506aa0394fa1f03d09a40cdabc5ade1215b0969 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 23 Aug 2022 14:49:37 +0100 Subject: [PATCH 01/22] jsondoclint: New Tool --- Cargo.lock | 4 ++++ Cargo.toml | 1 + src/bootstrap/test.rs | 2 ++ src/bootstrap/tool.rs | 1 + src/tools/compiletest/src/common.rs | 3 +++ src/tools/compiletest/src/main.rs | 2 ++ src/tools/compiletest/src/runtest.rs | 8 ++++++++ src/tools/jsondoclint/Cargo.toml | 8 ++++++++ src/tools/jsondoclint/src/main.rs | 1 + triagebot.toml | 2 ++ 10 files changed, 32 insertions(+) create mode 100644 src/tools/jsondoclint/Cargo.toml create mode 100644 src/tools/jsondoclint/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 4e0e72d34153f..93b622627b417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1891,6 +1891,10 @@ dependencies = [ "shlex", ] +[[package]] +name = "jsondoclint" +version = "0.1.0" + [[package]] name = "jsonpath_lib" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index 5753730053f4c..e49fe5e2f6356 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ members = [ "src/tools/unicode-table-generator", "src/tools/expand-yaml-anchors", "src/tools/jsondocck", + "src/tools/jsondoclint", "src/tools/html-checker", "src/tools/bump-stage0", "src/tools/replace-version-placeholder", diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f61c95830858f..9d286ddd6d164 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1341,6 +1341,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the let json_compiler = compiler.with_stage(0); cmd.arg("--jsondocck-path") .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target })); + cmd.arg("--jsondoclint-path") + .arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target })); } if mode == "run-make" { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index c3b04a9bbce3f..7d4ed24b64850 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -376,6 +376,7 @@ bootstrap_tool!( ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; LintDocs, "src/tools/lint-docs", "lint-docs"; JsonDocCk, "src/tools/jsondocck", "jsondocck"; + JsonDocLint, "src/tools/jsondoclint", "jsondoclint"; HtmlChecker, "src/tools/html-checker", "html-checker"; BumpStage0, "src/tools/bump-stage0", "bump-stage0"; ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6f17b9e1be9a3..64df76e27720d 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -203,6 +203,9 @@ pub struct Config { /// The jsondocck executable. pub jsondocck_path: Option, + /// The jsondoclint executable. + pub jsondoclint_path: Option, + /// The LLVM `FileCheck` binary path. pub llvm_filecheck: Option, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 0e2cc52a645bc..38c7b87fc0d9d 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -64,6 +64,7 @@ pub fn parse_config(args: Vec) -> Config { .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") .reqopt("", "python", "path to python to use for doc tests", "PATH") .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") + .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") @@ -226,6 +227,7 @@ pub fn parse_config(args: Vec) -> Config { rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), python: matches.opt_str("python").unwrap(), jsondocck_path: matches.opt_str("jsondocck-path"), + jsondoclint_path: matches.opt_str("jsondoclint-path"), valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e2afa5ef59020..9cbb6b7c393bd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2572,6 +2572,14 @@ impl<'test> TestCx<'test> { if !res.status.success() { self.fatal_proc_rec("check_missing_items failed!", &res); } + + let res = self.cmd2procres( + Command::new(self.config.jsondoclint_path.as_ref().unwrap()).arg(&json_out), + ); + + if !res.status.success() { + self.fatal_proc_rec("jsondoclint failed!", &res); + } } fn get_lines>( diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml new file mode 100644 index 0000000000000..42bb77fde41af --- /dev/null +++ b/src/tools/jsondoclint/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "jsondoclint" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/src/tools/jsondoclint/src/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 4b2dcc246e4ee..11caedbb9597a 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -132,6 +132,7 @@ trigger_files = [ "src/etc/htmldocck.py", "src/etc/check_missing_items.py", "src/tools/jsondocck", + "src/tools/jsondoclint", "src/tools/rustdoc-gui", "src/tools/rustdoc-js", "src/tools/rustdoc-themes", @@ -147,6 +148,7 @@ trigger_files = [ "src/rustdoc-json-types", "src/test/rustdoc-json", "src/tools/jsondocck", + "src/tools/jsondoclint", ] [autolabel."T-compiler"] From 404b60bf6b2e761188db0e0e5984a4065afaf9cf Mon Sep 17 00:00:00 2001 From: onestacked Date: Wed, 14 Sep 2022 01:42:40 +0200 Subject: [PATCH 02/22] Constify impl Fn* &(mut) Fn* --- library/core/src/ops/function.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index c5a194b7d0a41..827851c62ae7b 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -250,9 +250,10 @@ pub trait FnOnce { mod impls { #[stable(feature = "rust1", since = "1.0.0")] - impl Fn for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + impl const Fn for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call(&self, args: A) -> F::Output { (**self).call(args) @@ -260,9 +261,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + impl const FnMut for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (**self).call(args) @@ -270,9 +272,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + impl const FnOnce for &F where - F: Fn, + F: ~const Fn, { type Output = F::Output; @@ -282,9 +285,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &mut F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + impl const FnMut for &mut F where - F: FnMut, + F: ~const FnMut, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (*self).call_mut(args) @@ -292,9 +296,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &mut F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + impl const FnOnce for &mut F where - F: FnMut, + F: ~const FnMut, { type Output = F::Output; extern "rust-call" fn call_once(self, args: A) -> F::Output { From 478c471ce8aabb07e115f4caa18f4f1ca9acbc49 Mon Sep 17 00:00:00 2001 From: onestacked Date: Wed, 14 Sep 2022 15:10:02 +0200 Subject: [PATCH 03/22] Added Tracking Issue number. --- library/core/src/ops/function.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 827851c62ae7b..8fdf22cf6f2c8 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -250,7 +250,7 @@ pub trait FnOnce { mod impls { #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl const Fn for &F where F: ~const Fn, @@ -261,7 +261,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl const FnMut for &F where F: ~const Fn, @@ -272,7 +272,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl const FnOnce for &F where F: ~const Fn, @@ -285,7 +285,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl const FnMut for &mut F where F: ~const FnMut, @@ -296,7 +296,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "none")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl const FnOnce for &mut F where F: ~const FnMut, From c5b9cb43d9607811ecb5d90a1495871f5e5f3542 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 1 Sep 2022 11:40:43 +0100 Subject: [PATCH 04/22] errors: add `emit_note`/`create_note` Add `Noted` marker struct that implements `EmissionGuarantee` so that `emit_note` and `create_note` can be implemented for struct diagnostics. Signed-off-by: David Wood --- .../rustc_errors/src/diagnostic_builder.rs | 50 +++++++++++++++++++ compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_session/src/parse.rs | 13 ++++- compiler/rustc_session/src/session.rs | 10 ++++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 7e29dc207acce..a5b84ea2f0c95 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -232,6 +232,56 @@ impl EmissionGuarantee for () { } } +/// Marker type which enables implementation of `create_note` and `emit_note` functions for +/// note-without-error struct diagnostics. +#[derive(Copy, Clone)] +pub struct Noted; + +impl<'a> DiagnosticBuilder<'a, Noted> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + pub(crate) fn new_note(handler: &'a Handler, message: impl Into) -> Self { + let diagnostic = Diagnostic::new_with_code(Level::Note, None, message); + Self::new_diagnostic_note(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + }, + _marker: PhantomData, + } + } +} + +impl EmissionGuarantee for Noted { + fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + match db.inner.state { + // First `.emit()` call, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => { + db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + handler.emit_diagnostic(&mut db.inner.diagnostic); + } + // `.emit()` was previously called, disallowed from repeating it. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + } + + Noted + } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_note(handler, msg) + } +} + impl<'a> DiagnosticBuilder<'a, !> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 888128f3f74e7..3f8a46d247cb0 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -373,7 +373,7 @@ pub use diagnostic::{ AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; -pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder}; +pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder, Noted}; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 9bc7fbfbe1491..7b09272a9fea9 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -13,7 +13,7 @@ use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, - DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, MultiSpan, StashKey, + DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, MultiSpan, Noted, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -361,6 +361,17 @@ impl ParseSess { self.create_warning(warning).emit() } + pub fn create_note<'a>( + &'a self, + note: impl SessionDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + note.into_diagnostic(&self.span_diagnostic) + } + + pub fn emit_note<'a>(&'a self, note: impl SessionDiagnostic<'a, Noted>) -> Noted { + self.create_note(note).emit() + } + pub fn create_fatal<'a>( &'a self, fatal: impl SessionDiagnostic<'a, !>, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a001f87db00c6..36520a785d32f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -29,6 +29,7 @@ use rustc_errors::registry::Registry; use rustc_errors::{ error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, FluentBundle, Handler, LazyFallbackBundle, MultiSpan, + Noted, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -542,6 +543,15 @@ impl Session { pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { self.parse_sess.emit_warning(warning) } + pub fn create_note<'a>( + &'a self, + note: impl SessionDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + self.parse_sess.create_note(note) + } + pub fn emit_note<'a>(&'a self, note: impl SessionDiagnostic<'a, Noted>) -> Noted { + self.parse_sess.emit_note(note) + } pub fn create_fatal<'a>( &'a self, fatal: impl SessionDiagnostic<'a, !>, From 8a2f9c33e787149c45638a5bc50dee232244f6ef Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 30 Aug 2022 17:00:20 +0100 Subject: [PATCH 05/22] errors: implement `IntoDiagnosticArg` for `&T` Implement `IntoDiagnosticArg` for `&'a T` when `T` implements `IntoDiagnosticArg` and `Clone`. Makes it easier to write diagnostic structs that borrow something which implements `IntoDiagnosticArg`. Signed-off-by: David Wood --- .../rustc_borrowck/src/diagnostics/region_name.rs | 6 ++++++ compiler/rustc_borrowck/src/session_diagnostics.rs | 14 +------------- compiler/rustc_errors/src/diagnostic.rs | 6 ++++++ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 6c1eaa809c905..05b19fcfb999a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -187,6 +187,12 @@ impl Display for RegionName { } } +impl rustc_errors::IntoDiagnosticArg for RegionName { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId { self.body.source.def_id().expect_local() diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 5d750c6ca8c7b..cd890c96a7f15 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,4 +1,4 @@ -use rustc_errors::{IntoDiagnosticArg, MultiSpan}; +use rustc_errors::MultiSpan; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -137,18 +137,6 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> { }, } -impl IntoDiagnosticArg for &RegionName { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - format!("{}", self).into_diagnostic_arg() - } -} - -impl IntoDiagnosticArg for RegionName { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - format!("{}", self).into_diagnostic_arg() - } -} - #[derive(SessionSubdiagnostic)] pub(crate) enum RequireStaticErr { #[note(borrowck::used_impl_require_static)] diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a774b52c8a592..4abf97b2f949b 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -43,6 +43,12 @@ pub trait IntoDiagnosticArg { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; } +impl<'a, T: Clone + IntoDiagnosticArg> IntoDiagnosticArg for &'a T { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.clone().into_diagnostic_arg() + } +} + pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display); impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> { From ae5174122942f2d6797e5956cf658386cd13f170 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 30 Aug 2022 17:01:54 +0100 Subject: [PATCH 06/22] session: impl `IntoDiagnosticArg` for `CrateType` Forward the `Display` implementation for `CrateType` to `IntoDiagnosticArg` so that it can be used in diagnostic structs. Signed-off-by: David Wood --- compiler/rustc_session/src/config.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8bb3878fbbb47..cf250a27e2719 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -24,7 +24,7 @@ use rustc_span::RealFileName; use rustc_span::SourceFileHashAlgorithm; use rustc_errors::emitter::HumanReadableErrorType; -use rustc_errors::{ColorConfig, HandlerFlags}; +use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, @@ -2637,6 +2637,12 @@ impl fmt::Display for CrateType { } } +impl IntoDiagnosticArg for CrateType { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpSourceMode { /// `-Zunpretty=normal` From 7d7cd17cd842824204f803fd2b4fdeeecb222ff9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 30 Aug 2022 17:02:57 +0100 Subject: [PATCH 07/22] errors: impl `IntoDiagnosticArg` for `TargetTriple` Forward the `Display` implementation for `CrateType` to `IntoDiagnosticArg` so that it can be used in diagnostic structs. Signed-off-by: David Wood --- compiler/rustc_errors/Cargo.toml | 20 ++++++++++---------- compiler/rustc_errors/src/diagnostic.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index c36ca11fad6f2..dd96348153959 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -7,22 +7,22 @@ edition = "2021" doctest = false [dependencies] -tracing = "0.1" +annotate-snippets = "0.9" +atty = "0.2" +rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } +rustc_hir = { path = "../rustc_hir" } +rustc_lint_defs = { path = "../rustc_lint_defs" } +rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -rustc_macros = { path = "../rustc_macros" } -rustc_data_structures = { path = "../rustc_data_structures" } rustc_target = { path = "../rustc_target" } -rustc_hir = { path = "../rustc_hir" } -rustc_lint_defs = { path = "../rustc_lint_defs" } -unicode-width = "0.1.4" -atty = "0.2" -termcolor = "1.0" -annotate-snippets = "0.9" -termize = "0.1.1" serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" +termcolor = "1.0" +termize = "0.1.1" +tracing = "0.1" +unicode-width = "0.1.4" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 4abf97b2f949b..7675f805493f8 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -100,7 +100,7 @@ into_diagnostic_arg_using_display!( MacroRulesNormalizedIdent, ParseIntError, StackProtector, - &TargetTriple, + TargetTriple, SplitDebuginfo ); From 677d4d095827615124cd2387834507b0e5305d12 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 19 Aug 2022 14:48:15 +0100 Subject: [PATCH 08/22] session: diagnostic migration lint on more fns Apply the diagnostic migration lint to more functions on `Session`. Signed-off-by: David Wood --- compiler/rustc_driver/src/lib.rs | 3 ++ .../locales/en-US/interface.ftl | 10 +++++++ .../locales/en-US/monomorphize.ftl | 6 ++++ .../locales/en-US/session.ftl | 2 ++ compiler/rustc_errors/src/lib.rs | 6 ++++ compiler/rustc_interface/Cargo.toml | 4 +-- compiler/rustc_interface/src/errors.rs | 21 +++++++++++++ compiler/rustc_interface/src/util.rs | 27 ++++++++--------- compiler/rustc_monomorphize/src/collector.rs | 13 ++++---- compiler/rustc_monomorphize/src/errors.rs | 14 +++++++++ .../src/partitioning/mod.rs | 17 ++++------- compiler/rustc_session/src/errors.rs | 6 ++++ compiler/rustc_session/src/session.rs | 30 +++++++++++++++++-- 13 files changed, 122 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index d6f51d7eee1af..7b3dda6e8b4b4 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1205,6 +1205,9 @@ static DEFAULT_HOOK: LazyLock) + Sync + Send + /// /// When `install_ice_hook` is called, this function will be called as the panic /// hook. +// FIXME(translation): need struct diagnostics implemented on `Handler` +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); diff --git a/compiler/rustc_error_messages/locales/en-US/interface.ftl b/compiler/rustc_error_messages/locales/en-US/interface.ftl index bbcb8fc28cffa..c7ebb920ec84f 100644 --- a/compiler/rustc_error_messages/locales/en-US/interface.ftl +++ b/compiler/rustc_error_messages/locales/en-US/interface.ftl @@ -41,3 +41,13 @@ interface_rustc_error_unexpected_annotation = interface_failed_writing_file = failed to write file {$path}: {$error}" + +interface_unsupported_crate_type_for_target = + dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` + +interface_multiple_output_types_adaption = + due to multiple output types requested, the explicitly specified output file name will be adapted for each output type + +interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag + +interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag diff --git a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl index 42c84fdd2d14b..5839a47fb6708 100644 --- a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl +++ b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl @@ -24,3 +24,9 @@ monomorphize_large_assignments = monomorphize_requires_lang_item = requires `{$lang_item}` lang_item + +monomorphize_encountered_error_while_instantiating = + the above error was encountered while instantiating `{$formatted_item}` + +monomorphize_unknown_cgu_collection_mode = + unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index 76cae3c81e451..bffd720b39d0c 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -66,3 +66,5 @@ session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has session_crate_name_empty = crate name must not be empty session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` + +session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3f8a46d247cb0..ddc9ff8a9f922 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -936,6 +936,7 @@ impl Handler { self.emit_diag_at_span(Diagnostic::new(Bug, msg), span); } + #[rustc_lint_diagnostics] pub fn span_note_without_error( &self, span: impl Into, @@ -944,6 +945,7 @@ impl Handler { self.emit_diag_at_span(Diagnostic::new(Note, msg), span); } + #[rustc_lint_diagnostics] pub fn span_note_diag( &self, span: Span, @@ -955,19 +957,23 @@ impl Handler { } // NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread + #[rustc_lint_diagnostics] pub fn fatal(&self, msg: impl Into) -> FatalError { self.inner.borrow_mut().fatal(msg) } + #[rustc_lint_diagnostics] pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { self.inner.borrow_mut().err(msg) } + #[rustc_lint_diagnostics] pub fn warn(&self, msg: impl Into) { let mut db = DiagnosticBuilder::new(self, Warning(None), msg); db.emit(); } + #[rustc_lint_diagnostics] pub fn note_without_error(&self, msg: impl Into) { DiagnosticBuilder::new(self, Note, msg).emit(); } diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index da4002d09ad02..39fad22635d8e 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -45,6 +45,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_privacy = { path = "../rustc_privacy" } rustc_query_impl = { path = "../rustc_query_impl" } rustc_resolve = { path = "../rustc_resolve" } +rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } @@ -54,9 +55,6 @@ libc = "0.2" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["libloaderapi"] } -[dev-dependencies] -rustc_target = { path = "../rustc_target" } - [features] llvm = ['rustc_codegen_llvm'] rustc_use_parallel_compiler = ['rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler'] diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index 6a497aed4aba7..9ca4831438bfe 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -1,5 +1,7 @@ use rustc_macros::SessionDiagnostic; +use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; +use rustc_target::spec::TargetTriple; use std::io; use std::path::Path; @@ -87,3 +89,22 @@ pub struct FailedWritingFile<'a> { pub path: &'a Path, pub error: io::Error, } + +#[derive(SessionDiagnostic)] +#[diag(interface::unsupported_crate_type_for_target)] +pub struct UnsupportedCrateTypeForTarget<'a> { + pub crate_type: CrateType, + pub target_triple: &'a TargetTriple, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::multiple_output_types_adaption)] +pub struct MultipleOutputTypesAdaption; + +#[derive(SessionDiagnostic)] +#[diag(interface::ignoring_extra_filename)] +pub struct IgnoringExtraFilename; + +#[derive(SessionDiagnostic)] +#[diag(interface::ignoring_out_dir)] +pub struct IgnoringOutDir; diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f7e70d355cf86..033a59ae8effd 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,3 +1,4 @@ +use crate::errors; use info; use libloading::Library; use rustc_ast as ast; @@ -572,16 +573,15 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec 1 { - sess.warn( - "due to multiple output types requested, the explicitly specified \ - output file name will be adapted for each output type", - ); + sess.emit_warning(errors::MultipleOutputTypesAdaption); None } else { if !sess.opts.cg.extra_filename.is_empty() { - sess.warn("ignoring -C extra-filename flag due to -o flag"); + sess.emit_warning(errors::IgnoringExtraFilename); } Some(out_file.clone()) }; if *odir != None { - sess.warn("ignoring --out-dir flag due to -o flag"); + sess.emit_warning(errors::IgnoringOutDir); } OutputFilenames::new( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index be74a9d11e3c5..f746f8f70ff09 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -201,7 +201,10 @@ use std::iter; use std::ops::Range; use std::path::PathBuf; -use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit}; +use crate::errors::{ + EncounteredErrorWhileInstantiating, LargeAssignmentsLint, RecursionLimit, RequiresLangItem, + TypeLengthLimit, +}; #[derive(PartialEq)] pub enum MonoItemCollectionMode { @@ -524,10 +527,10 @@ fn collect_items_rec<'tcx>( && starting_point.node.is_user_defined() { let formatted_item = with_no_trimmed_paths!(starting_point.node.to_string()); - tcx.sess.span_note_without_error( - starting_point.span, - &format!("the above error was encountered while instantiating `{}`", formatted_item), - ); + tcx.sess.emit_note(EncounteredErrorWhileInstantiating { + span: starting_point.span, + formatted_item, + }); } inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items); diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index d5f05e790d388..cb8675cc69186 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -83,3 +83,17 @@ pub struct SymbolAlreadyDefined { pub span: Option, pub symbol: String, } + +#[derive(SessionDiagnostic)] +#[diag(monomorphize::encountered_error_while_instantiating)] +pub struct EncounteredErrorWhileInstantiating { + #[primary_span] + pub span: Span, + pub formatted_item: String, +} + +#[derive(SessionDiagnostic)] +#[diag(monomorphize::unknown_cgu_collection_mode)] +pub struct UnknownCguCollectionMode<'a> { + pub mode: &'a str, +} diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 932edc6675f59..c124d5635900b 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -108,7 +108,7 @@ use rustc_span::symbol::Symbol; use crate::collector::InliningMap; use crate::collector::{self, MonoItemCollectionMode}; -use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy}; +use crate::errors::{SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy}; pub struct PartitioningCx<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -345,18 +345,13 @@ fn collect_and_partition_mono_items<'tcx>( ) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { let collection_mode = match tcx.sess.opts.unstable_opts.print_mono_items { Some(ref s) => { - let mode_string = s.to_lowercase(); - let mode_string = mode_string.trim(); - if mode_string == "eager" { + let mode = s.to_lowercase(); + let mode = mode.trim(); + if mode == "eager" { MonoItemCollectionMode::Eager } else { - if mode_string != "lazy" { - let message = format!( - "Unknown codegen-item collection mode '{}'. \ - Falling back to 'lazy' mode.", - mode_string - ); - tcx.sess.warn(&message); + if mode != "lazy" { + tcx.sess.emit_warning(UnknownCguCollectionMode { mode }); } MonoItemCollectionMode::Lazy diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index c6596ff249899..723ffa6ab9e9e 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -219,3 +219,9 @@ impl crate::SessionDiagnostic<'_> for InvalidCharacterInCrateName<'_> { diag } } + +#[derive(SessionDiagnostic)] +#[diag(session::optimization_fuel_exhausted)] +pub struct OptimisationFuelExhausted { + pub msg: String, +} diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 36520a785d32f..79621f0be2868 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -4,8 +4,8 @@ pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath}; use crate::errors::{ CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported, - NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, - SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, + NotCircumventFeature, OptimisationFuelExhausted, ProfileSampleUseFileDoesNotExist, + ProfileUseFileDoesNotExist, SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget, TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion, }; @@ -510,6 +510,8 @@ impl Session { self.diagnostic().span_err_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { self.diagnostic().err(msg) } @@ -595,11 +597,19 @@ impl Session { Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) } } + + // #[allow(rustc::untranslatable_diagnostic)] + // #[allow(rustc::diagnostic_outside_of_impl)] + #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn>(&self, sp: S, msg: impl Into) { self.diagnostic().span_warn(sp, msg) } + + // #[allow(rustc::untranslatable_diagnostic)] + // #[allow(rustc::diagnostic_outside_of_impl)] + #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn_with_code>( @@ -610,6 +620,10 @@ impl Session { ) { self.diagnostic().span_warn_with_code(sp, msg, code) } + + #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn warn(&self, msg: impl Into) { self.diagnostic().warn(msg) } @@ -640,9 +654,15 @@ impl Session { self.diagnostic().delay_good_path_bug(msg) } + #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn note_without_error(&self, msg: impl Into) { self.diagnostic().note_without_error(msg) } + #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_note_without_error>( &self, sp: S, @@ -650,6 +670,10 @@ impl Session { ) { self.diagnostic().span_note_without_error(sp, msg) } + + // #[allow(rustc::untranslatable_diagnostic)] + // #[allow(rustc::diagnostic_outside_of_impl)] + #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_note_without_error( @@ -879,7 +903,7 @@ impl Session { // We only call `msg` in case we can actually emit warnings. // Otherwise, this could cause a `delay_good_path_bug` to // trigger (issue #79546). - self.warn(&format!("optimization-fuel-exhausted: {}", msg())); + self.emit_warning(OptimisationFuelExhausted { msg: msg() }); } fuel.out_of_fuel = true; } else if fuel.remaining > 0 { From b058e41fcc17ff889d1c4682cd9a52d81db19b67 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 19 Aug 2022 14:47:41 +0100 Subject: [PATCH 09/22] incremental: migrate diagnostics Migrate the `rustc_incremental` crate's diagnostics to translatable diagnostic structs. Signed-off-by: David Wood --- .../locales/en-US/incremental.ftl | 106 +++++ compiler/rustc_error_messages/src/lib.rs | 13 +- .../rustc_incremental/src/assert_dep_graph.rs | 40 +- .../src/assert_module_sources.rs | 50 +-- compiler/rustc_incremental/src/errors.rs | 364 ++++++++++++++++++ compiler/rustc_incremental/src/lib.rs | 4 + .../src/persist/dirty_clean.rs | 63 ++- .../src/persist/file_format.rs | 21 +- compiler/rustc_incremental/src/persist/fs.rs | 111 +----- .../rustc_incremental/src/persist/load.rs | 54 ++- .../rustc_incremental/src/persist/save.rs | 24 +- .../src/persist/work_product.rs | 18 +- compiler/rustc_session/src/session.rs | 6 - .../incremental-session-fail/Makefile | 2 +- 14 files changed, 611 insertions(+), 265 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/incremental.ftl create mode 100644 compiler/rustc_incremental/src/errors.rs diff --git a/compiler/rustc_error_messages/locales/en-US/incremental.ftl b/compiler/rustc_error_messages/locales/en-US/incremental.ftl new file mode 100644 index 0000000000000..ed9a22c02d181 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/incremental.ftl @@ -0,0 +1,106 @@ +incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} + +incremental_missing_depnode = missing `DepNode` variant + +incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected + +incremental_no_path = no path from `{$source}` to `{$target}` + +incremental_ok = OK + +incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified + +incremental_missing_query_depgraph = found CGU-reuse attribute but `-Zquery-dep-graph` was not specified + +incremental_malformed_cgu_name = + found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). + +incremental_no_module_named = no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} + +incremental_field_associated_value_expected = associated value expected for `{$name}` + +incremental_no_field = no field `{$name}` + +incremental_assertion_auto = `except` specified DepNodes that can not be affected for \"{$name}\": \"{$e}\" + +incremental_undefined_clean_dirty_assertions_item = clean/dirty auto-assertions not yet defined for Node::Item.node={$kind} + +incremental_undefined_clean_dirty_assertions = clean/dirty auto-assertions not yet defined for {$kind} + +incremental_repeated_depnode_label = dep-node label `{$label}` is repeated + +incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized + +incremental_not_dirty = `{$dep_node_str}` should be dirty but is not + +incremental_not_clean = `{$dep_node_str}` should be clean but is not + +incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not + +incremental_unknown_item = unknown item `{$name}` + +incremental_no_cfg = no cfg attribute + +incremental_associated_value_expected_for = associated value expected for `{$ident}` + +incremental_associated_value_expected = expected an associated value + +incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute + +incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err} + +incremental_create_new = failed to create {$name} at `{$path}`: {$err} + +incremental_write_new = failed to write {$name} to `{$path}`: {$err} + +incremental_canonicalize_path = incremental compilation: error canonicalizing path `{$path}`: {$err} + +incremental_create_incr_comp_dir = could not create incremental compilation {$tag} directory `{$path}`: {$err} + +incremental_create_lock = incremental compilation: could not create session directory lock file: {$lock_err} + .lock_unsupported = the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation + .cargo_help_1 = incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental) + .cargo_help_2 = the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir) + +incremental_delete_lock = error deleting lock file for incremental compilation session directory `{$path}`: {$err} + +incremental_hard_link_failed = + hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}` + +incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err} + +incremental_delete_full = error deleting incremental compilation session directory `{$path}`: {$err} + +incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err} + +incremental_invalid_gc_failed = + failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err} + +incremental_finalized_gc_failed = + failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err} + +incremental_session_gc_failed = + failed to garbage collect incremental compilation session directory `{$path}`: {$err} + +incremental_assert_not_loaded = + we asserted that the incremental cache should not be loaded, but it was loaded + +incremental_assert_loaded = + we asserted that an existing incremental cache directory should be successfully loaded, but it was not + +incremental_delete_incompatible = + failed to delete invalidated or incompatible incremental compilation session directory contents `{$path}`: {$err} + +incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err} + +incremental_decode_incr_cache = could not decode incremental cache: {$err} + +incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err} + +incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err} + +incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err} + +incremental_copy_workproduct_to_cache = error copying object file `{$from}` to incremental directory as `{$to}`: {$err} + +incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err} diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index b6e0f3faa73cb..5ab3a17d34beb 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -43,24 +43,25 @@ fluent_messages! { const_eval => "../locales/en-US/const_eval.ftl", driver => "../locales/en-US/driver.ftl", expand => "../locales/en-US/expand.ftl", - session => "../locales/en-US/session.ftl", - interface => "../locales/en-US/interface.ftl", + incremental => "../locales/en-US/incremental.ftl", infer => "../locales/en-US/infer.ftl", + interface => "../locales/en-US/interface.ftl", lint => "../locales/en-US/lint.ftl", + metadata => "../locales/en-US/metadata.ftl", middle => "../locales/en-US/middle.ftl", + mir_dataflow => "../locales/en-US/mir_dataflow.ftl", monomorphize => "../locales/en-US/monomorphize.ftl", - metadata => "../locales/en-US/metadata.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", query_system => "../locales/en-US/query_system.ftl", - trait_selection => "../locales/en-US/trait_selection.ftl", save_analysis => "../locales/en-US/save_analysis.ftl", + session => "../locales/en-US/session.ftl", + symbol_mangling => "../locales/en-US/symbol_mangling.ftl", + trait_selection => "../locales/en-US/trait_selection.ftl", ty_utils => "../locales/en-US/ty_utils.ftl", typeck => "../locales/en-US/typeck.ftl", - mir_dataflow => "../locales/en-US/mir_dataflow.ftl", - symbol_mangling => "../locales/en-US/symbol_mangling.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 69e482ce854c0..95b48c38218d0 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -33,6 +33,7 @@ //! fn baz() { foo(); } //! ``` +use crate::errors; use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING}; @@ -133,12 +134,10 @@ impl<'tcx> IfThisChanged<'tcx> { Some(n) => { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { Ok(n) => n, - Err(()) => { - self.tcx.sess.span_fatal( - attr.span, - &format!("unrecognized DepNode variant {:?}", n), - ); - } + Err(()) => self.tcx.sess.emit_fatal(errors::UnrecognizedDepNode { + span: attr.span, + name: n, + }), } } }; @@ -149,16 +148,14 @@ impl<'tcx> IfThisChanged<'tcx> { Some(n) => { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { Ok(n) => n, - Err(()) => { - self.tcx.sess.span_fatal( - attr.span, - &format!("unrecognized DepNode variant {:?}", n), - ); - } + Err(()) => self.tcx.sess.emit_fatal(errors::UnrecognizedDepNode { + span: attr.span, + name: n, + }), } } None => { - self.tcx.sess.span_fatal(attr.span, "missing DepNode variant"); + self.tcx.sess.emit_fatal(errors::MissingDepNode { span: attr.span }); } }; self.then_this_would_need.push(( @@ -204,7 +201,7 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou // Return early here so as not to construct the query, which is not cheap. if if_this_changed.is_empty() { for &(target_span, _, _, _) in then_this_would_need { - tcx.sess.span_err(target_span, "no `#[rustc_if_this_changed]` annotation detected"); + tcx.sess.emit_err(errors::MissingIfThisChanged { span: target_span }); } return; } @@ -213,16 +210,13 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou let dependents = query.transitive_predecessors(source_dep_node); for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need { if !dependents.contains(&target_dep_node) { - tcx.sess.span_err( - target_span, - &format!( - "no path from `{}` to `{}`", - tcx.def_path_str(source_def_id), - target_pass - ), - ); + tcx.sess.emit_err(errors::NoPath { + span: target_span, + source: tcx.def_path_str(source_def_id), + target: *target_pass, + }); } else { - tcx.sess.span_err(target_span, "OK"); + tcx.sess.emit_err(errors::Ok { span: target_span }); } } } diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 89d419bc8e90f..2968a0e1203a9 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -22,6 +22,7 @@ //! allows for doing a more fine-grained check to see if pre- or post-lto data //! was re-used. +use crate::errors; use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LOCAL_CRATE; @@ -66,10 +67,9 @@ impl<'tcx> AssertModuleSource<'tcx> { sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact), sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast), other => { - self.tcx.sess.span_fatal( - attr.span, - &format!("unknown cgu-reuse-kind `{}` specified", other), - ); + self.tcx + .sess + .emit_fatal(errors::UnknownReuseKind { span: attr.span, kind: other }); } } } else { @@ -77,10 +77,7 @@ impl<'tcx> AssertModuleSource<'tcx> { }; if !self.tcx.sess.opts.unstable_opts.query_dep_graph { - self.tcx.sess.span_fatal( - attr.span, - "found CGU-reuse attribute but `-Zquery-dep-graph` was not specified", - ); + self.tcx.sess.emit_fatal(errors::MissingQueryDepGraph { span: attr.span }); } if !self.check_config(attr) { @@ -92,13 +89,11 @@ impl<'tcx> AssertModuleSource<'tcx> { let crate_name = self.tcx.crate_name(LOCAL_CRATE).to_string(); if !user_path.starts_with(&crate_name) { - let msg = format!( - "Found malformed codegen unit name `{}`. \ - Codegen units names must always start with the name of the \ - crate (`{}` in this case).", - user_path, crate_name - ); - self.tcx.sess.span_fatal(attr.span, &msg); + self.tcx.sess.emit_fatal(errors::MalformedCguName { + span: attr.span, + user_path, + crate_name, + }); } // Split of the "special suffix" if there is one. @@ -125,15 +120,12 @@ impl<'tcx> AssertModuleSource<'tcx> { let mut cgu_names: Vec<&str> = self.available_cgus.iter().map(|cgu| cgu.as_str()).collect(); cgu_names.sort(); - self.tcx.sess.span_err( - attr.span, - &format!( - "no module named `{}` (mangled: {}). Available modules: {}", - user_path, - cgu_name, - cgu_names.join(", ") - ), - ); + self.tcx.sess.emit_err(errors::NoModuleNamed { + span: attr.span, + user_path, + cgu_name, + cgu_names: cgu_names.join(", "), + }); } self.tcx.sess.cgu_reuse_tracker.set_expectation( @@ -151,15 +143,15 @@ impl<'tcx> AssertModuleSource<'tcx> { if let Some(value) = item.value_str() { return value; } else { - self.tcx.sess.span_fatal( - item.span(), - &format!("associated value expected for `{}`", name), - ); + self.tcx.sess.emit_fatal(errors::FieldAssociatedValueExpected { + span: item.span(), + name, + }); } } } - self.tcx.sess.span_fatal(attr.span, &format!("no field `{}`", name)); + self.tcx.sess.emit_fatal(errors::NoField { span: attr.span, name }); } /// Scan for a `cfg="foo"` attribute and check whether we have a diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs new file mode 100644 index 0000000000000..a15cff22f8756 --- /dev/null +++ b/compiler/rustc_incremental/src/errors.rs @@ -0,0 +1,364 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::{symbol::Ident, Span, Symbol}; +use std::path::{Path, PathBuf}; + +#[derive(SessionDiagnostic)] +#[diag(incremental::unrecognized_depnode)] +pub struct UnrecognizedDepNode { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::missing_depnode)] +pub struct MissingDepNode { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::missing_if_this_changed)] +pub struct MissingIfThisChanged { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::ok)] +pub struct Ok { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::no_path)] +pub struct NoPath { + #[primary_span] + pub span: Span, + pub target: Symbol, + pub source: String, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::unknown_reuse_kind)] +pub struct UnknownReuseKind { + #[primary_span] + pub span: Span, + pub kind: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::missing_query_depgraph)] +pub struct MissingQueryDepGraph { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::malformed_cgu_name)] +pub struct MalformedCguName { + #[primary_span] + pub span: Span, + pub user_path: String, + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::no_module_named)] +pub struct NoModuleNamed<'a> { + #[primary_span] + pub span: Span, + pub user_path: &'a str, + pub cgu_name: Symbol, + pub cgu_names: String, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::field_associated_value_expected)] +pub struct FieldAssociatedValueExpected { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::no_field)] +pub struct NoField { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::assertion_auto)] +pub struct AssertionAuto<'a> { + #[primary_span] + pub span: Span, + pub name: &'a str, + pub e: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::undefined_clean_dirty_assertions_item)] +pub struct UndefinedCleanDirtyItem { + #[primary_span] + pub span: Span, + pub kind: String, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::undefined_clean_dirty_assertions)] +pub struct UndefinedCleanDirty { + #[primary_span] + pub span: Span, + pub kind: String, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::repeated_depnode_label)] +pub struct RepeatedDepNodeLabel<'a> { + #[primary_span] + pub span: Span, + pub label: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::unrecognized_depnode_label)] +pub struct UnrecognizedDepNodeLabel<'a> { + #[primary_span] + pub span: Span, + pub label: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::not_dirty)] +pub struct NotDirty<'a> { + #[primary_span] + pub span: Span, + pub dep_node_str: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::not_clean)] +pub struct NotClean<'a> { + #[primary_span] + pub span: Span, + pub dep_node_str: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::not_loaded)] +pub struct NotLoaded<'a> { + #[primary_span] + pub span: Span, + pub dep_node_str: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::unknown_item)] +pub struct UnknownItem { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::no_cfg)] +pub struct NoCfg { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::associated_value_expected_for)] +pub struct AssociatedValueExpectedFor { + #[primary_span] + pub span: Span, + pub ident: Ident, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::associated_value_expected)] +pub struct AssociatedValueExpected { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::unchecked_clean)] +pub struct UncheckedClean { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::delete_old)] +pub struct DeleteOld<'a> { + pub name: &'a str, + pub path: PathBuf, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::create_new)] +pub struct CreateNew<'a> { + pub name: &'a str, + pub path: PathBuf, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::write_new)] +pub struct WriteNew<'a> { + pub name: &'a str, + pub path: PathBuf, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::canonicalize_path)] +pub struct CanonicalizePath { + pub path: PathBuf, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::create_incr_comp_dir)] +pub struct CreateIncrCompDir<'a> { + pub tag: &'a str, + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::create_lock)] +pub struct CreateLock<'a> { + pub lock_err: std::io::Error, + pub session_dir: &'a Path, + #[note(incremental::lock_unsupported)] + pub is_unsupported_lock: Option<()>, + #[help(incremental::cargo_help_1)] + #[help(incremental::cargo_help_2)] + pub is_cargo: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::delete_lock)] +pub struct DeleteLock<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::hard_link_failed)] +pub struct HardLinkFailed<'a> { + pub path: &'a Path, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::delete_partial)] +pub struct DeletePartial<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::delete_full)] +pub struct DeleteFull<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::finalize)] +pub struct Finalize<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::invalid_gc_failed)] +pub struct InvalidGcFailed<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::finalized_gc_failed)] +pub struct FinalizedGcFailed<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::session_gc_failed)] +pub struct SessionGcFailed<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::assert_not_loaded)] +pub struct AssertNotLoaded; + +#[derive(SessionDiagnostic)] +#[diag(incremental::assert_loaded)] +pub struct AssertLoaded; + +#[derive(SessionDiagnostic)] +#[diag(incremental::delete_incompatible)] +pub struct DeleteIncompatible { + pub path: PathBuf, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::load_dep_graph)] +pub struct LoadDepGraph { + pub path: PathBuf, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::decode_incr_cache)] +pub struct DecodeIncrCache { + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::write_dep_graph)] +pub struct WriteDepGraph<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::move_dep_graph)] +pub struct MoveDepGraph<'a> { + pub from: &'a Path, + pub to: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::create_dep_graph)] +pub struct CreateDepGraph<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::copy_workproduct_to_cache)] +pub struct CopyWorkProductToCache<'a> { + pub from: &'a Path, + pub to: &'a Path, + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(incremental::delete_workproduct)] +pub struct DeleteWorkProduct<'a> { + pub path: &'a Path, + pub err: std::io::Error, +} diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 1e88e8091c373..dc4a80519247b 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -3,8 +3,11 @@ #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(let_else)] +#![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; @@ -13,6 +16,7 @@ extern crate tracing; mod assert_dep_graph; pub mod assert_module_sources; +mod errors; mod persist; use assert_dep_graph::assert_dep_graph; diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 710c4a01b244f..4c815d69ff395 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -19,6 +19,7 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. +use crate::errors; use rustc_ast::{self as ast, Attribute, NestedMetaItem}; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LocalDefId; @@ -198,11 +199,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let loaded_from_disk = self.loaded_from_disk(attr); for e in except.iter() { if !auto.remove(e) { - let msg = format!( - "`except` specified DepNodes that can not be affected for \"{}\": \"{}\"", - name, e - ); - self.tcx.sess.span_fatal(attr.span, &msg); + self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e }); } } Assertion { clean: auto, dirty: except, loaded_from_disk } @@ -284,14 +281,10 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { // An implementation, eg `impl Trait for Foo { .. }` HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL), - _ => self.tcx.sess.span_fatal( - attr.span, - &format!( - "clean/dirty auto-assertions not yet defined \ - for Node::Item.node={:?}", - item.kind - ), - ), + _ => self.tcx.sess.emit_fatal(errors::UndefinedCleanDirtyItem { + span: attr.span, + kind: format!("{:?}", item.kind), + }), } } HirNode::TraitItem(item) => match item.kind { @@ -304,10 +297,10 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL), ImplItemKind::TyAlias(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), }, - _ => self.tcx.sess.span_fatal( - attr.span, - &format!("clean/dirty auto-assertions not yet defined for {:?}", node), - ), + _ => self.tcx.sess.emit_fatal(errors::UndefinedCleanDirty { + span: attr.span, + kind: format!("{:?}", node), + }), }; let labels = Labels::from_iter(labels.iter().flat_map(|s| s.iter().map(|l| (*l).to_string()))); @@ -320,16 +313,15 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let label = label.trim(); if DepNode::has_label_string(label) { if out.contains(label) { - self.tcx.sess.span_fatal( - item.span(), - &format!("dep-node label `{}` is repeated", label), - ); + self.tcx + .sess + .emit_fatal(errors::RepeatedDepNodeLabel { span: item.span(), label }); } out.insert(label.to_string()); } else { self.tcx .sess - .span_fatal(item.span(), &format!("dep-node label `{}` not recognized", label)); + .emit_fatal(errors::UnrecognizedDepNodeLabel { span: item.span(), label }); } } out @@ -350,7 +342,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let dep_node_str = self.dep_node_str(&dep_node); self.tcx .sess - .span_err(item_span, &format!("`{}` should be dirty but is not", dep_node_str)); + .emit_err(errors::NotDirty { span: item_span, dep_node_str: &dep_node_str }); } } @@ -361,7 +353,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let dep_node_str = self.dep_node_str(&dep_node); self.tcx .sess - .span_err(item_span, &format!("`{}` should be clean but is not", dep_node_str)); + .emit_err(errors::NotClean { span: item_span, dep_node_str: &dep_node_str }); } } @@ -370,10 +362,9 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) { let dep_node_str = self.dep_node_str(&dep_node); - self.tcx.sess.span_err( - item_span, - &format!("`{}` should have been loaded from disk but it was not", dep_node_str), - ); + self.tcx + .sess + .emit_err(errors::NotLoaded { span: item_span, dep_node_str: &dep_node_str }); } } @@ -414,12 +405,12 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) { - tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty())); + tcx.sess.emit_err(errors::UnknownItem { span: attr.span, name: item.name_or_empty() }); } } match cfg { - None => tcx.sess.span_fatal(attr.span, "no cfg attribute"), + None => tcx.sess.emit_fatal(errors::NoCfg { span: attr.span }), Some(c) => c, } } @@ -428,13 +419,11 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { if let Some(value) = item.value_str() { value } else { - let msg = if let Some(ident) = item.ident() { - format!("associated value expected for `{}`", ident) + if let Some(ident) = item.ident() { + tcx.sess.emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident }); } else { - "expected an associated value".to_string() - }; - - tcx.sess.span_fatal(item.span(), &msg); + tcx.sess.emit_fatal(errors::AssociatedValueExpected { span: item.span() }); + } } } @@ -458,7 +447,7 @@ impl<'tcx> FindAllAttrs<'tcx> { fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet) { for attr in &self.found_attrs { if !checked_attrs.contains(&attr.id) { - self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute"); + self.tcx.sess.emit_err(errors::UncheckedClean { span: attr.span }); checked_attrs.insert(attr.id); } } diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 2dbd4b6bce85a..dc981c6179eeb 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -9,15 +9,15 @@ //! compiler versions don't change frequently for the typical user, being //! conservative here practically has no downside. -use std::env; -use std::fs; -use std::io::{self, Read}; -use std::path::{Path, PathBuf}; - +use crate::errors; use rustc_data_structures::memmap::Mmap; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encoder; use rustc_session::Session; +use std::env; +use std::fs; +use std::io::{self, Read}; +use std::path::{Path, PathBuf}; /// The first few bytes of files generated by incremental compilation. const FILE_MAGIC: &[u8] = b"RSIC"; @@ -60,12 +60,7 @@ where } Err(err) if err.kind() == io::ErrorKind::NotFound => (), Err(err) => { - sess.err(&format!( - "unable to delete old {} at `{}`: {}", - name, - path_buf.display(), - err - )); + sess.emit_err(errors::DeleteOld { name, path: path_buf, err }); return; } } @@ -73,7 +68,7 @@ where let mut encoder = match FileEncoder::new(&path_buf) { Ok(encoder) => encoder, Err(err) => { - sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err)); + sess.emit_err(errors::CreateNew { name, path: path_buf, err }); return; } }; @@ -90,7 +85,7 @@ where debug!("save: data written to disk successfully"); } Err(err) => { - sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err)); + sess.emit_err(errors::WriteNew { name, path: path_buf, err }); } } } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 25c1b2e1c4387..b7fe3263adc9f 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -103,6 +103,7 @@ //! unsupported file system and emit a warning in that case. This is not yet //! implemented. +use crate::errors; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::{base_n, flock}; @@ -225,12 +226,7 @@ pub fn prepare_session_directory( let crate_dir = match crate_dir.canonicalize() { Ok(v) => v, Err(err) => { - let reported = sess.err(&format!( - "incremental compilation: error canonicalizing path `{}`: {}", - crate_dir.display(), - err - )); - return Err(reported); + return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err })); } }; @@ -273,14 +269,7 @@ pub fn prepare_session_directory( debug!("successfully copied data from: {}", source_directory.display()); if !allows_links { - sess.warn(&format!( - "Hard linking files in the incremental \ - compilation cache failed. Copying files \ - instead. Consider moving the cache \ - directory to a file system which supports \ - hard linking in session dir `{}`", - session_dir.display() - )); + sess.emit_warning(errors::HardLinkFailed { path: &session_dir }); } sess.init_incr_comp_session(session_dir, directory_lock, true); @@ -295,12 +284,7 @@ pub fn prepare_session_directory( // Try to remove the session directory we just allocated. We don't // know if there's any garbage in it from the failed copy action. if let Err(err) = safe_remove_dir_all(&session_dir) { - sess.warn(&format!( - "Failed to delete partly initialized \ - session dir `{}`: {}", - session_dir.display(), - err - )); + sess.emit_warning(errors::DeletePartial { path: &session_dir, err }); } delete_session_dir_lock_file(sess, &lock_file_path); @@ -332,12 +316,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { ); if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) { - sess.warn(&format!( - "Error deleting incremental compilation \ - session directory `{}`: {}", - incr_comp_session_dir.display(), - err - )); + sess.emit_warning(errors::DeleteFull { path: &incr_comp_session_dir, err }); } let lock_file_path = lock_file_path(&*incr_comp_session_dir); @@ -380,12 +359,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { } Err(e) => { // Warn about the error. However, no need to abort compilation now. - sess.warn(&format!( - "Error finalizing incremental compilation \ - session directory `{}`: {}", - incr_comp_session_dir.display(), - e - )); + sess.emit_warning(errors::Finalize { path: &incr_comp_session_dir, err: e }); debug!("finalize_session_directory() - error, marking as invalid"); // Drop the file lock, so we can garage collect @@ -488,16 +462,7 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorGua debug!("{} directory created successfully", dir_tag); Ok(()) } - Err(err) => { - let reported = sess.err(&format!( - "Could not create incremental compilation {} \ - directory `{}`: {}", - dir_tag, - path.display(), - err - )); - Err(reported) - } + Err(err) => Err(sess.emit_err(errors::CreateIncrCompDir { tag: dir_tag, path, err })), } } @@ -518,46 +483,20 @@ fn lock_directory( // the lock should be exclusive Ok(lock) => Ok((lock, lock_file_path)), Err(lock_err) => { - let mut err = sess.struct_err(&format!( - "incremental compilation: could not create \ - session directory lock file: {}", - lock_err - )); - if flock::Lock::error_unsupported(&lock_err) { - err.note(&format!( - "the filesystem for the incremental path at {} \ - does not appear to support locking, consider changing the \ - incremental path to a filesystem that supports locking \ - or disable incremental compilation", - session_dir.display() - )); - if std::env::var_os("CARGO").is_some() { - err.help( - "incremental compilation can be disabled by setting the \ - environment variable CARGO_INCREMENTAL=0 (see \ - https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)", - ); - err.help( - "the entire build directory can be changed to a different \ - filesystem by setting the environment variable CARGO_TARGET_DIR \ - to a different path (see \ - https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)", - ); - } - } - Err(err.emit()) + let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err).then_some(()); + Err(sess.emit_err(errors::CreateLock { + lock_err, + session_dir, + is_unsupported_lock, + is_cargo: std::env::var_os("CARGO").map(|_| ()), + })) } } } fn delete_session_dir_lock_file(sess: &Session, lock_file_path: &Path) { if let Err(err) = safe_remove_file(&lock_file_path) { - sess.warn(&format!( - "Error deleting lock file for incremental \ - compilation session directory `{}`: {}", - lock_file_path.display(), - err - )); + sess.emit_warning(errors::DeleteLock { path: lock_file_path, err }); } } @@ -774,12 +713,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { if !lock_file_to_session_dir.values().any(|dir| *dir == directory_name) { let path = crate_directory.join(directory_name); if let Err(err) = safe_remove_dir_all(&path) { - sess.warn(&format!( - "Failed to garbage collect invalid incremental \ - compilation session directory `{}`: {}", - path.display(), - err - )); + sess.emit_warning(errors::InvalidGcFailed { path: &path, err }); } } } @@ -885,12 +819,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); if let Err(err) = safe_remove_dir_all(&path) { - sess.warn(&format!( - "Failed to garbage collect finalized incremental \ - compilation session directory `{}`: {}", - path.display(), - err - )); + sess.emit_warning(errors::FinalizedGcFailed { path: &path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(&path)); } @@ -907,11 +836,7 @@ fn delete_old(sess: &Session, path: &Path) { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); if let Err(err) = safe_remove_dir_all(&path) { - sess.warn(&format!( - "Failed to garbage collect incremental compilation session directory `{}`: {}", - path.display(), - err - )); + sess.emit_warning(errors::SessionGcFailed { path: &path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(&path)); } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 1c5fd91690230..d5097065dda2e 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,5 +1,6 @@ //! Code to save/load the dep-graph from files. +use crate::errors; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; @@ -8,7 +9,7 @@ use rustc_serialize::opaque::MemDecoder; use rustc_serialize::Decodable; use rustc_session::config::IncrementalStateAssertion; use rustc_session::Session; -use std::path::Path; +use std::path::{Path, PathBuf}; use super::data::*; use super::file_format; @@ -27,11 +28,10 @@ pub enum LoadResult { }, /// The file either didn't exist or was produced by an incompatible compiler version. DataOutOfDate, - /// An error occurred. - Error { - #[allow(missing_docs)] - message: String, - }, + /// Loading the dep graph failed. + LoadDepGraph(PathBuf, std::io::Error), + /// Decoding loaded incremental cache failed. + DecodeIncrCache(Box), } impl LoadResult { @@ -40,36 +40,31 @@ impl LoadResult { // Check for errors when using `-Zassert-incremental-state` match (sess.opts.assert_incr_state, &self) { (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => { - sess.fatal( - "We asserted that the incremental cache should not be loaded, \ - but it was loaded.", - ); + sess.emit_fatal(errors::AssertNotLoaded); } ( Some(IncrementalStateAssertion::Loaded), - LoadResult::Error { .. } | LoadResult::DataOutOfDate, + LoadResult::LoadDepGraph(..) + | LoadResult::DecodeIncrCache(..) + | LoadResult::DataOutOfDate, ) => { - sess.fatal( - "We asserted that an existing incremental cache directory should \ - be successfully loaded, but it was not.", - ); + sess.emit_fatal(errors::AssertLoaded); } _ => {} }; match self { - LoadResult::Error { message } => { - sess.warn(&message); + LoadResult::LoadDepGraph(path, err) => { + sess.emit_warning(errors::LoadDepGraph { path, err }); + Default::default() + } + LoadResult::DecodeIncrCache(err) => { + sess.emit_warning(errors::DecodeIncrCache { err: format!("{err:?}") }); Default::default() } LoadResult::DataOutOfDate => { if let Err(err) = delete_all_session_dir_contents(sess) { - sess.err(&format!( - "Failed to delete invalidated or incompatible \ - incremental compilation session directory contents `{}`: {}.", - dep_graph_path(sess).display(), - err - )); + sess.emit_err(errors::DeleteIncompatible { path: dep_graph_path(sess), err }); } Default::default() } @@ -90,9 +85,7 @@ fn load_data( // compiler version. Neither is an error. LoadResult::DataOutOfDate } - Err(err) => LoadResult::Error { - message: format!("could not load dep-graph from `{}`: {}", path.display(), err), - }, + Err(err) => LoadResult::LoadDepGraph(path.to_path_buf(), err), } } @@ -114,9 +107,9 @@ impl MaybeAsync> { pub fn open(self) -> LoadResult { match self { MaybeAsync::Sync(result) => result, - MaybeAsync::Async(handle) => handle.join().unwrap_or_else(|e| LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e), - }), + MaybeAsync::Async(handle) => { + handle.join().unwrap_or_else(|e| LoadResult::DecodeIncrCache(e)) + } } } } @@ -185,7 +178,8 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { match load_data(report_incremental_info, &path, nightly_build) { LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, - LoadResult::Error { message } => LoadResult::Error { message }, + LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err), + LoadResult::DecodeIncrCache(err) => LoadResult::DecodeIncrCache(err), LoadResult::Ok { data: (bytes, start_pos) } => { let mut decoder = MemDecoder::new(&bytes, start_pos); let prev_commandline_args_hash = u64::decode(&mut decoder); diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 710350314975c..7731351a80b7c 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -1,3 +1,4 @@ +use crate::errors; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::join; use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; @@ -59,19 +60,14 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { move || { sess.time("incr_comp_persist_dep_graph", || { if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) { - sess.err(&format!( - "failed to write dependency graph to `{}`: {}", - staging_dep_graph_path.display(), - err - )); + sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err }); } if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) { - sess.err(&format!( - "failed to move dependency graph from `{}` to `{}`: {}", - staging_dep_graph_path.display(), - dep_graph_path.display(), - err - )); + sess.emit_err(errors::MoveDepGraph { + from: &staging_dep_graph_path, + to: &dep_graph_path, + err, + }); } }); }, @@ -163,11 +159,7 @@ pub fn build_dep_graph( let mut encoder = match FileEncoder::new(&path_buf) { Ok(encoder) => encoder, Err(err) => { - sess.err(&format!( - "failed to create dependency graph at `{}`: {}", - path_buf.display(), - err - )); + sess.emit_err(errors::CreateDepGraph { path: &path_buf, err }); return None; } }; diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index 2f1853c441eee..dc98fbeb0d166 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -2,6 +2,7 @@ //! //! [work products]: WorkProduct +use crate::errors; use crate::persist::fs::*; use rustc_data_structures::fx::FxHashMap; use rustc_fs_util::link_or_copy; @@ -28,12 +29,11 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( let _ = saved_files.insert(ext.to_string(), file_name); } Err(err) => { - sess.warn(&format!( - "error copying object file `{}` to incremental directory as `{}`: {}", - path.display(), - path_in_incr_dir.display(), - err - )); + sess.emit_warning(errors::CopyWorkProductToCache { + from: &path, + to: &path_in_incr_dir, + err, + }); } } } @@ -49,11 +49,7 @@ pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) { for (_, path) in &work_product.saved_files { let path = in_incr_comp_dir_sess(sess, path); if let Err(err) = std_fs::remove_file(&path) { - sess.warn(&format!( - "file-system error deleting outdated file `{}`: {}", - path.display(), - err - )); + sess.emit_warning(errors::DeleteWorkProduct { path: &path, err }); } } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 79621f0be2868..78b5f08a2cbc3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -598,8 +598,6 @@ impl Session { } } - // #[allow(rustc::untranslatable_diagnostic)] - // #[allow(rustc::diagnostic_outside_of_impl)] #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] @@ -607,8 +605,6 @@ impl Session { self.diagnostic().span_warn(sp, msg) } - // #[allow(rustc::untranslatable_diagnostic)] - // #[allow(rustc::diagnostic_outside_of_impl)] #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] @@ -671,8 +667,6 @@ impl Session { self.diagnostic().span_note_without_error(sp, msg) } - // #[allow(rustc::untranslatable_diagnostic)] - // #[allow(rustc::diagnostic_outside_of_impl)] #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] diff --git a/src/test/run-make/incremental-session-fail/Makefile b/src/test/run-make/incremental-session-fail/Makefile index 0461bb926e76e..6ce1370927bc1 100644 --- a/src/test/run-make/incremental-session-fail/Makefile +++ b/src/test/run-make/incremental-session-fail/Makefile @@ -9,6 +9,6 @@ all: touch $(SESSION_DIR) # Check exit code is 1 for an error, and not 101 for ICE. $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ] - $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE) + $(CGREP) "could not create incremental compilation crate directory" < $(OUTPUT_FILE) # -v tests are fragile, hopefully this text won't change $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE) From d7b9221405c7f852663a7c5bef660582cb5cd972 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Mon, 12 Sep 2022 10:57:34 +0300 Subject: [PATCH 10/22] change AccessLevels representation --- .../locales/en-US/privacy.ftl | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_middle/src/middle/privacy.rs | 93 ++++++++++- compiler/rustc_passes/src/dead.rs | 11 +- compiler/rustc_passes/src/reachable.rs | 10 +- compiler/rustc_privacy/src/errors.rs | 4 +- compiler/rustc_privacy/src/lib.rs | 37 ++++- compiler/rustc_resolve/src/access_levels.rs | 12 +- compiler/rustc_span/src/symbol.rs | 2 +- src/librustdoc/core.rs | 5 +- src/librustdoc/visit_ast.rs | 2 +- src/librustdoc/visit_lib.rs | 4 +- src/test/ui/privacy/access_levels.rs | 69 ++++---- src/test/ui/privacy/access_levels.stderr | 151 ++++++++---------- 14 files changed, 249 insertions(+), 155 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl index da987152ff660..a26d1b2b381e8 100644 --- a/compiler/rustc_error_messages/locales/en-US/privacy.ftl +++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl @@ -11,7 +11,7 @@ privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interfac .label = can't leak {$vis_descr} {$kind} .visibility_label = `{$descr}` declared as {$vis_descr} -privacy_report_access_level = {$descr} +privacy_report_effective_visibility = {$descr} privacy_from_private_dep_in_public_interface = {$kind} `{$descr}` from private dependency '{$krate}' in public interface diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 8d88a90e39564..2512fbbd1b878 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -756,7 +756,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes, Testing: // ========================================================================== - rustc_attr!(TEST, rustc_access_level, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 751c7f4648225..c595fbec0dd5c 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -1,7 +1,7 @@ //! A pass that checks to make sure private fields and methods aren't used //! outside their scopes. This pass will also generate a set of exported items //! which are available for use externally when compiled as a library. - +use crate::ty::Visibility; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; @@ -27,26 +27,107 @@ pub enum AccessLevel { Public, } +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Default)] +pub struct EffectiveVisibility { + public: Option, + exported: Option, + reachable: Option, + reachable_from_impl_trait: Option, +} + +impl EffectiveVisibility { + pub fn get(&self, tag: AccessLevel) -> Option<&Visibility> { + match tag { + AccessLevel::Public => &self.public, + AccessLevel::Exported => &self.exported, + AccessLevel::Reachable => &self.reachable, + AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait, + } + .as_ref() + } + + fn get_mut(&mut self, tag: AccessLevel) -> &mut Option { + match tag { + AccessLevel::Public => &mut self.public, + AccessLevel::Exported => &mut self.exported, + AccessLevel::Reachable => &mut self.reachable, + AccessLevel::ReachableFromImplTrait => &mut self.reachable_from_impl_trait, + } + } + + pub fn is_public_at_level(&self, tag: AccessLevel) -> bool { + self.get(tag).map_or(false, |vis| vis.is_public()) + } +} + /// Holds a map of accessibility levels for reachable HIR nodes. #[derive(Debug, Clone)] pub struct AccessLevels { - pub map: FxHashMap, + map: FxHashMap, } -impl AccessLevels { +impl AccessLevels { + pub fn is_public_at_level(&self, id: Id, tag: AccessLevel) -> bool { + self.get_effective_vis(id) + .map_or(false, |effective_vis| effective_vis.is_public_at_level(tag)) + } + /// See `AccessLevel::Reachable`. pub fn is_reachable(&self, id: Id) -> bool { - self.map.get(&id) >= Some(&AccessLevel::Reachable) + self.is_public_at_level(id, AccessLevel::Reachable) } /// See `AccessLevel::Exported`. pub fn is_exported(&self, id: Id) -> bool { - self.map.get(&id) >= Some(&AccessLevel::Exported) + self.is_public_at_level(id, AccessLevel::Exported) } /// See `AccessLevel::Public`. pub fn is_public(&self, id: Id) -> bool { - self.map.get(&id) >= Some(&AccessLevel::Public) + self.is_public_at_level(id, AccessLevel::Public) + } + + pub fn get_access_level(&self, id: Id) -> Option { + self.get_effective_vis(id).and_then(|effective_vis| { + for level in [ + AccessLevel::Public, + AccessLevel::Exported, + AccessLevel::Reachable, + AccessLevel::ReachableFromImplTrait, + ] { + if effective_vis.is_public_at_level(level) { + return Some(level); + } + } + None + }) + } + + pub fn set_access_level(&mut self, id: Id, tag: AccessLevel) { + let mut effective_vis = self.get_effective_vis(id).copied().unwrap_or_default(); + for level in [ + AccessLevel::Public, + AccessLevel::Exported, + AccessLevel::Reachable, + AccessLevel::ReachableFromImplTrait, + ] { + if level <= tag { + *effective_vis.get_mut(level) = Some(Visibility::Public); + } + } + self.map.insert(id, effective_vis); + } + + pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> { + self.map.get(&id) + } + + pub fn iter(&self) -> impl Iterator { + self.map.iter() + } + + pub fn map_id(&self, f: impl Fn(Id) -> OutId) -> AccessLevels { + AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() } } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index f141d7beeb921..57f7c379d0490 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::privacy; +use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; @@ -619,13 +619,10 @@ fn create_and_seed_worklist<'tcx>( // see `MarkSymbolVisitor::struct_constructors` let mut struct_constructors = Default::default(); let mut worklist = access_levels - .map .iter() - .filter_map( - |(&id, &level)| { - if level >= privacy::AccessLevel::Reachable { Some(id) } else { None } - }, - ) + .filter_map(|(&id, effective_vis)| { + effective_vis.is_public_at_level(AccessLevel::Reachable).then_some(id) + }) // Seed entry point .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local())) .collect::>(); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index f7e3fac6b2e20..75244124e20ef 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; -use rustc_middle::middle::privacy; +use rustc_middle::middle::privacy::{self, AccessLevel}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::config::CrateType; @@ -373,7 +373,13 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet { // If other crates link to us, they're going to expect to be able to // use the lang items, so we need to be sure to mark them as // exported. - reachable_context.worklist.extend(access_levels.map.keys()); + reachable_context.worklist = access_levels + .iter() + .filter_map(|(&id, effective_vis)| { + effective_vis.is_public_at_level(AccessLevel::ReachableFromImplTrait).then_some(id) + }) + .collect::>(); + for item in tcx.lang_items().items().iter() { if let Some(def_id) = *item { if let Some(def_id) = def_id.as_local() { diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index 63f83f8965ec5..705ad567aa779 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -76,8 +76,8 @@ pub struct InPublicInterface<'a> { } #[derive(SessionDiagnostic)] -#[diag(privacy::report_access_level)] -pub struct ReportAccessLevel { +#[diag(privacy::report_effective_visibility)] +pub struct ReportEffectiveVisibility { #[primary_span] pub span: Span, pub descr: String, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index afd423dc5fa1a..9a1603fb835ee 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -43,7 +43,7 @@ use std::{cmp, fmt, mem}; use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, - InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportAccessLevel, + InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportEffectiveVisibility, UnnamedItemIsPrivate, }; @@ -377,7 +377,7 @@ impl VisibilityLike for Option { // (which require reaching the `DefId`s in them). const SHALLOW: bool = true; fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { - cmp::min(find.access_levels.map.get(&def_id).copied(), find.min) + cmp::min(find.access_levels.get_access_level(def_id), find.min) } } @@ -417,7 +417,7 @@ struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> { impl<'tcx> EmbargoVisitor<'tcx> { fn get(&self, def_id: LocalDefId) -> Option { - self.access_levels.map.get(&def_id).copied() + self.access_levels.get_access_level(def_id) } fn update_with_hir_id( @@ -434,7 +434,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { let old_level = self.get(def_id); // Accessibility levels can only grow. if level > old_level { - self.access_levels.map.insert(def_id, level.unwrap()); + self.access_levels.set_access_level(def_id, level.unwrap()); self.changed = true; level } else { @@ -915,10 +915,31 @@ pub struct TestReachabilityVisitor<'tcx, 'a> { impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { fn access_level_diagnostic(&mut self, def_id: LocalDefId) { - if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_access_level) { - let access_level = format!("{:?}", self.access_levels.map.get(&def_id)); - let span = self.tcx.def_span(def_id.to_def_id()); - self.tcx.sess.emit_err(ReportAccessLevel { span, descr: access_level }); + let span = self.tcx.def_span(def_id.to_def_id()); + if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) { + let mut error_msg = String::new(); + + let effective_vis = + self.access_levels.get_effective_vis(def_id).copied().unwrap_or_default(); + for level in [ + AccessLevel::Public, + AccessLevel::Exported, + AccessLevel::Reachable, + AccessLevel::ReachableFromImplTrait, + ] { + let vis_str = match effective_vis.get(level) { + Some(ty::Visibility::Restricted(restricted_id)) => { + format!("pub({})", self.tcx.item_name(restricted_id.to_def_id())) + } + Some(ty::Visibility::Public) => "pub".to_string(), + None => "pub(self)".to_string(), + }; + if level != AccessLevel::Public { + error_msg.push_str(", "); + } + error_msg.push_str(&format!("{:?}: {}", level, vis_str)); + } + self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg }); } } } diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs index 0a3add2e0f532..9b1111c02c73f 100644 --- a/compiler/rustc_resolve/src/access_levels.rs +++ b/compiler/rustc_resolve/src/access_levels.rs @@ -46,7 +46,7 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level). fn set_bindings_access_level(&mut self, module_id: LocalDefId) { assert!(self.r.module_map.contains_key(&&module_id.to_def_id())); - let module_level = self.r.access_levels.map.get(&module_id).copied(); + let module_level = self.r.access_levels.get_access_level(module_id); if !module_level.is_some() { return; } @@ -103,9 +103,9 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { def_id: LocalDefId, access_level: Option, ) -> Option { - let old_level = self.r.access_levels.map.get(&def_id).copied(); + let old_level = self.r.access_levels.get_access_level(def_id); if old_level < access_level { - self.r.access_levels.map.insert(def_id, access_level.unwrap()); + self.r.access_levels.set_access_level(def_id, access_level.unwrap()); self.changed = true; access_level } else { @@ -131,7 +131,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { // Foreign modules inherit level from parents. ast::ItemKind::ForeignMod(..) => { let parent_level = - self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied(); + self.r.access_levels.get_access_level(self.r.local_parent(def_id)); self.set_access_level(item.id, parent_level); } @@ -151,7 +151,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { self.set_bindings_access_level(def_id); for variant in variants { let variant_def_id = self.r.local_def_id(variant.id); - let variant_level = self.r.access_levels.map.get(&variant_def_id).copied(); + let variant_level = self.r.access_levels.get_access_level(variant_def_id); for field in variant.data.fields() { self.set_access_level(field.id, variant_level); } @@ -159,7 +159,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { } ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { - let inherited_level = self.r.access_levels.map.get(&def_id).copied(); + let inherited_level = self.r.access_levels.get_access_level(def_id); for field in def.fields() { if field.vis.kind.is_pub() { self.set_access_level(field.id, inherited_level); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5bddcd3481974..530198d8ad8cf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1211,7 +1211,6 @@ symbols! { rust_eh_unregister_frames, rust_oom, rustc, - rustc_access_level, rustc_allocator, rustc_allocator_nounwind, rustc_allocator_zeroed, @@ -1239,6 +1238,7 @@ symbols! { rustc_dump_program_clauses, rustc_dump_user_substs, rustc_dump_vtable, + rustc_effective_visibility, rustc_error, rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c48b25aea4a37..76562d26a5502 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -10,7 +10,6 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Path, TraitCandidate}; use rustc_interface::interface; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; use rustc_session::config::{self, CrateType, ErrorOutputType}; @@ -364,9 +363,7 @@ pub(crate) fn run_global_ctxt( .copied() .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)) .collect(); - let access_levels = AccessLevels { - map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(), - }; + let access_levels = tcx.privacy_access_levels(()).map_id(Into::into); let mut ctxt = DocContext { tcx, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c27ac0ac40e1d..e6cef4a326ac0 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -230,7 +230,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } else { // All items need to be handled here in case someone wishes to link // to them with intra-doc links - self.cx.cache.access_levels.map.insert(did, AccessLevel::Public); + self.cx.cache.access_levels.set_access_level(did, AccessLevel::Public); } } } diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index f01ec38665c01..8221e0998d79a 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -38,10 +38,10 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { fn update(&mut self, did: DefId, level: Option) -> Option { let is_hidden = self.tcx.is_doc_hidden(did); - let old_level = self.access_levels.map.get(&did).cloned(); + let old_level = self.access_levels.get_access_level(did); // Accessibility levels can only grow if level > old_level && !is_hidden { - self.access_levels.map.insert(did, level.unwrap()); + self.access_levels.set_access_level(did, level.unwrap()); level } else { old_level diff --git a/src/test/ui/privacy/access_levels.rs b/src/test/ui/privacy/access_levels.rs index d51d2b57267b6..aa718ab9254df 100644 --- a/src/test/ui/privacy/access_levels.rs +++ b/src/test/ui/privacy/access_levels.rs @@ -1,49 +1,62 @@ #![feature(rustc_attrs)] -#[rustc_access_level] mod outer { //~ ERROR None - #[rustc_access_level] pub mod inner { //~ ERROR Some(Exported) - #[rustc_access_level] - extern "C" { //~ ERROR Some(Exported) - #[rustc_access_level] static a: u8; //~ ERROR None - #[rustc_access_level] pub fn b(); //~ ERROR Some(Exported) - } - #[rustc_access_level] - pub trait Trait { //~ ERROR Some(Exported) - #[rustc_access_level] const A: i32; //~ ERROR Some(Exported) - #[rustc_access_level] type B; //~ ERROR Some(Exported) +#[rustc_effective_visibility] +mod outer { //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) + #[rustc_effective_visibility] + pub mod inner1 { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + + #[rustc_effective_visibility] + extern "C" {} //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + + #[rustc_effective_visibility] + pub trait PubTrait { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + #[rustc_effective_visibility] + const A: i32; //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + #[rustc_effective_visibility] + type B; //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub } - #[rustc_access_level] - pub struct Struct { //~ ERROR Some(Exported) - #[rustc_access_level] a: u8, //~ ERROR None - #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported) - } + #[rustc_effective_visibility] + struct PrivStruct; //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) - #[rustc_access_level] - pub union Union { //~ ERROR Some(Exported) - #[rustc_access_level] a: u8, //~ ERROR None - #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported) + #[rustc_effective_visibility] + pub union PubUnion { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + #[rustc_effective_visibility] + a: u8, //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) + #[rustc_effective_visibility] + pub b: u8, //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub } - #[rustc_access_level] - pub enum Enum { //~ ERROR Some(Exported) - #[rustc_access_level] A( //~ ERROR Some(Exported) - #[rustc_access_level] Struct, //~ ERROR Some(Exported) - #[rustc_access_level] Union, //~ ERROR Some(Exported) + #[rustc_effective_visibility] + pub enum Enum { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + #[rustc_effective_visibility] + A( //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + #[rustc_effective_visibility] + PubUnion, //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub ), } } - #[rustc_access_level] macro_rules! none_macro { //~ ERROR None + #[rustc_effective_visibility] + macro_rules! none_macro { //~ Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) () => {}; } #[macro_export] - #[rustc_access_level] macro_rules! public_macro { //~ ERROR Some(Public) + #[rustc_effective_visibility] + macro_rules! public_macro { //~ Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub () => {}; } + + #[rustc_effective_visibility] + pub struct ReachableStruct { //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub + #[rustc_effective_visibility] + pub a: u8, //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub + } } -pub use outer::inner; +pub use outer::inner1; + +pub fn foo() -> outer::ReachableStruct { outer::ReachableStruct {a: 0} } fn main() {} diff --git a/src/test/ui/privacy/access_levels.stderr b/src/test/ui/privacy/access_levels.stderr index f326293c384a5..2ed6c330a2f97 100644 --- a/src/test/ui/privacy/access_levels.stderr +++ b/src/test/ui/privacy/access_levels.stderr @@ -1,125 +1,104 @@ -error: None - --> $DIR/access_levels.rs:3:23 +error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) + --> $DIR/access_levels.rs:4:1 | -LL | #[rustc_access_level] mod outer { - | ^^^^^^^^^ +LL | mod outer { + | ^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:4:27 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:6:5 | -LL | #[rustc_access_level] pub mod inner { - | ^^^^^^^^^^^^^ +LL | pub mod inner1 { + | ^^^^^^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:6:9 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:9:9 | -LL | / extern "C" { -LL | | #[rustc_access_level] static a: u8; -LL | | #[rustc_access_level] pub fn b(); -LL | | } - | |_________^ +LL | extern "C" {} + | ^^^^^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:11:9 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:12:9 | -LL | pub trait Trait { - | ^^^^^^^^^^^^^^^ +LL | pub trait PubTrait { + | ^^^^^^^^^^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:17:9 +error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) + --> $DIR/access_levels.rs:20:9 | -LL | pub struct Struct { +LL | struct PrivStruct; | ^^^^^^^^^^^^^^^^^ -error: None - --> $DIR/access_levels.rs:18:35 - | -LL | #[rustc_access_level] a: u8, - | ^^^^^ - -error: Some(Exported) - --> $DIR/access_levels.rs:19:35 - | -LL | #[rustc_access_level] pub b: u8, - | ^^^^^^^^^ - -error: Some(Exported) +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub --> $DIR/access_levels.rs:23:9 | -LL | pub union Union { - | ^^^^^^^^^^^^^^^ +LL | pub union PubUnion { + | ^^^^^^^^^^^^^^^^^^ -error: None - --> $DIR/access_levels.rs:24:35 +error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) + --> $DIR/access_levels.rs:25:13 | -LL | #[rustc_access_level] a: u8, - | ^^^^^ +LL | a: u8, + | ^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:25:35 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:27:13 | -LL | #[rustc_access_level] pub b: u8, - | ^^^^^^^^^ +LL | pub b: u8, + | ^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:29:9 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:31:9 | LL | pub enum Enum { | ^^^^^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:30:35 - | -LL | #[rustc_access_level] A( - | ^ - -error: Some(Exported) - --> $DIR/access_levels.rs:31:39 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:33:13 | -LL | #[rustc_access_level] Struct, - | ^^^^^^ +LL | A( + | ^ -error: Some(Exported) - --> $DIR/access_levels.rs:32:39 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:35:17 | -LL | #[rustc_access_level] Union, - | ^^^^^ +LL | PubUnion, + | ^^^^^^^^ -error: None - --> $DIR/access_levels.rs:37:27 +error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self) + --> $DIR/access_levels.rs:41:5 | -LL | #[rustc_access_level] macro_rules! none_macro { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | macro_rules! none_macro { + | ^^^^^^^^^^^^^^^^^^^^^^^ -error: Some(Public) - --> $DIR/access_levels.rs:42:27 +error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:47:5 | -LL | #[rustc_access_level] macro_rules! public_macro { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | macro_rules! public_macro { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:12:35 +error: Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:52:5 | -LL | #[rustc_access_level] const A: i32; - | ^^^^^^^^^^^^ +LL | pub struct ReachableStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:13:35 +error: Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:54:9 | -LL | #[rustc_access_level] type B; - | ^^^^^^ +LL | pub a: u8, + | ^^^^^^^^^ -error: None - --> $DIR/access_levels.rs:7:35 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:14:13 | -LL | #[rustc_access_level] static a: u8; - | ^^^^^^^^^^^^ +LL | const A: i32; + | ^^^^^^^^^^^^ -error: Some(Exported) - --> $DIR/access_levels.rs:8:35 +error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub + --> $DIR/access_levels.rs:16:13 | -LL | #[rustc_access_level] pub fn b(); - | ^^^^^^^^^^ +LL | type B; + | ^^^^^^ -error: aborting due to 20 previous errors +error: aborting due to 17 previous errors From a7a4fe9ffac69ec96b8ba6ec3da8fd4673dfef6b Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 24 Aug 2022 17:32:39 +0100 Subject: [PATCH 11/22] jsondoclint: Tree Walk Validator --- Cargo.lock | 18 +- src/tools/jsondoclint/Cargo.toml | 4 + src/tools/jsondoclint/src/item_kind.rs | 29 ++ src/tools/jsondoclint/src/main.rs | 34 ++- src/tools/jsondoclint/src/validator.rs | 391 +++++++++++++++++++++++++ 5 files changed, 469 insertions(+), 7 deletions(-) create mode 100644 src/tools/jsondoclint/src/item_kind.rs create mode 100644 src/tools/jsondoclint/src/validator.rs diff --git a/Cargo.lock b/Cargo.lock index 93b622627b417..69f96bcbe63b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.60" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "array_tool" @@ -1362,9 +1362,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.5.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431" +checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50" [[package]] name = "fs_extra" @@ -1894,6 +1894,12 @@ dependencies = [ [[package]] name = "jsondoclint" version = "0.1.0" +dependencies = [ + "anyhow", + "fs-err", + "rustdoc-json-types", + "serde_json", +] [[package]] name = "jsonpath_lib" @@ -4449,9 +4455,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "indexmap", "itoa", diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml index 42bb77fde41af..84a6c7f96c464 100644 --- a/src/tools/jsondoclint/Cargo.toml +++ b/src/tools/jsondoclint/Cargo.toml @@ -6,3 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.62" +fs-err = "2.8.1" +rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" } +serde_json = "1.0.85" diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs new file mode 100644 index 0000000000000..7c6c0b5437928 --- /dev/null +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -0,0 +1,29 @@ +use rustdoc_json_types::ItemEnum; + +pub(crate) fn can_appear_in_mod(kind: &ItemEnum) -> bool { + match kind { + ItemEnum::Module(_) => true, + ItemEnum::ExternCrate { .. } => true, + ItemEnum::Import(_) => true, + ItemEnum::Union(_) => true, + ItemEnum::Struct(_) => true, + ItemEnum::StructField(_) => false, // Only in structs or variants + ItemEnum::Enum(_) => true, + ItemEnum::Variant(_) => false, // Only in enums + ItemEnum::Function(_) => true, + ItemEnum::Trait(_) => true, + ItemEnum::TraitAlias(_) => true, + ItemEnum::Method(_) => false, // Only in traits + ItemEnum::Impl(_) => true, + ItemEnum::Typedef(_) => true, + ItemEnum::OpaqueTy(_) => todo!("IDK"), // On + ItemEnum::Constant(_) => true, + ItemEnum::Static(_) => true, + ItemEnum::ForeignType => todo!("IDK"), + ItemEnum::Macro(_) => true, + ItemEnum::ProcMacro(_) => true, + ItemEnum::PrimitiveType(_) => todo!("IDK"), + ItemEnum::AssocConst { .. } => false, // Trait Only + ItemEnum::AssocType { .. } => false, // Trait only + } +} diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index f328e4d9d04c3..b98601f7d89f9 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -1 +1,33 @@ -fn main() {} +use std::env; + +use anyhow::{anyhow, bail, Result}; +use fs_err as fs; +use rustdoc_json_types::{Crate, Id, FORMAT_VERSION}; + +pub(crate) mod item_kind; +mod validator; + +#[derive(Debug)] +struct Error { + message: String, + id: Id, +} + +fn main() -> Result<()> { + let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?; + let contents = fs::read_to_string(path)?; + let krate: Crate = serde_json::from_str(&contents)?; + assert_eq!(krate.format_version, FORMAT_VERSION); + + let mut validator = validator::Validator::new(&krate); + validator.check_crate(); + + if !validator.errs.is_empty() { + for err in validator.errs { + eprintln!("`{}`: `{}`", err.id.0, err.message); + } + bail!("Errors validating json"); + } + + Ok(()) +} diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs new file mode 100644 index 0000000000000..2bb63bc3a44e5 --- /dev/null +++ b/src/tools/jsondoclint/src/validator.rs @@ -0,0 +1,391 @@ +use std::collections::HashSet; +use std::hash::Hash; + +use rustdoc_json_types::{ + Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs, + GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Method, Module, OpaqueTy, + Path, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding, + TypeBindingKind, Typedef, Union, Variant, WherePredicate, +}; + +use crate::{item_kind::can_appear_in_mod, Error}; + +#[derive(Debug)] +pub struct Validator<'a> { + pub(crate) errs: Vec, + krate: &'a Crate, + seen_ids: HashSet<&'a Id>, + todo: HashSet<&'a Id>, +} + +fn set_remove(set: &mut HashSet) -> Option { + if let Some(id) = set.iter().next() { + let id = id.clone(); + set.take(&id) + } else { + None + } +} + +impl<'a> Validator<'a> { + pub fn new(krate: &'a Crate) -> Self { + Self { krate, errs: Vec::new(), seen_ids: HashSet::new(), todo: HashSet::new() } + } + + pub fn check_crate(&mut self) { + let root = &self.krate.root; + self.add_mod_id(root); + while let Some(id) = set_remove(&mut self.todo) { + self.seen_ids.insert(id); + self.check_item(id); + } + } + + fn check_item(&mut self, id: &'a Id) { + let item = &self.krate.index[id]; + match &item.inner { + ItemEnum::Import(x) => self.check_import(x), + ItemEnum::Union(x) => self.check_union(x), + ItemEnum::Struct(x) => self.check_struct(x), + ItemEnum::StructField(x) => self.check_struct_field(x), + ItemEnum::Enum(x) => self.check_enum(x), + ItemEnum::Variant(x) => self.check_variant(x), + ItemEnum::Function(x) => self.check_function(x), + ItemEnum::Trait(x) => self.check_trait(x), + ItemEnum::TraitAlias(x) => self.check_trait_alias(x), + ItemEnum::Method(x) => self.check_method(x), + ItemEnum::Impl(x) => self.check_impl(x), + ItemEnum::Typedef(x) => self.check_typedef(x), + ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x), + ItemEnum::Constant(x) => self.check_constant(x), + ItemEnum::Static(x) => self.check_static(x), + ItemEnum::ForeignType => todo!(), + ItemEnum::Macro(x) => self.check_macro(x), + ItemEnum::ProcMacro(x) => self.check_proc_macro(x), + ItemEnum::PrimitiveType(x) => self.check_primitive_type(x), + ItemEnum::Module(x) => self.check_module(x), + + ItemEnum::ExternCrate { .. } => todo!(), + ItemEnum::AssocConst { .. } => todo!(), + ItemEnum::AssocType { .. } => todo!(), + } + } + + // Core checkers + fn check_module(&mut self, module: &'a Module) { + module.items.iter().for_each(|i| self.add_mod_item_id(i)); + } + + fn check_import(&mut self, x: &'a Import) { + if x.glob { + self.add_mod_id(x.id.as_ref().unwrap()); + } else if let Some(id) = &x.id { + self.add_mod_item_id(id); + } + } + + fn check_union(&mut self, x: &'a Union) { + self.check_generics(&x.generics); + x.fields.iter().for_each(|i| self.add_field_id(i)); + x.impls.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_struct(&mut self, x: &'a Struct) { + self.check_generics(&x.generics); + match &x.kind { + StructKind::Unit => {} + StructKind::Tuple(fields) => fields.iter().flatten().for_each(|f| self.add_field_id(f)), + StructKind::Plain { fields, fields_stripped: _ } => { + fields.iter().for_each(|f| self.add_field_id(f)) + } + } + x.impls.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_struct_field(&mut self, x: &'a Type) { + self.check_type(x); + } + + fn check_enum(&mut self, x: &'a Enum) { + self.check_generics(&x.generics); + x.variants.iter().for_each(|i| self.add_variant_id(i)); + x.impls.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_variant(&mut self, x: &'a Variant) { + match x { + Variant::Plain(_discriminant) => {} // TODO: Check discriminant value parses + Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)), + Variant::Struct { fields, fields_stripped: _ } => { + fields.iter().for_each(|f| self.add_field_id(f)) + } + } + } + + fn check_function(&mut self, x: &'a Function) { + self.check_generics(&x.generics); + self.check_fn_decl(&x.decl); + } + + fn check_trait(&mut self, x: &'a Trait) { + self.check_generics(&x.generics); + x.items.iter().for_each(|i| self.add_trait_item_id(i)); + x.bounds.iter().for_each(|i| self.check_generic_bound(i)); + x.implementations.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_trait_alias(&mut self, x: &'a TraitAlias) { + self.check_generics(&x.generics); + x.params.iter().for_each(|i| self.check_generic_bound(i)); + } + + fn check_method(&mut self, x: &'a Method) { + self.check_fn_decl(&x.decl); + self.check_generics(&x.generics); + } + + fn check_impl(&mut self, x: &'a Impl) { + self.check_generics(&x.generics); + if let Some(path) = &x.trait_ { + self.check_path(path); // TODO: Check is trait. + } + self.check_type(&x.for_); + x.items.iter().for_each(|i| self.add_trait_item_id(i)); + if let Some(blanket_impl) = &x.blanket_impl { + self.check_type(blanket_impl) + } + } + + fn check_typedef(&mut self, x: &'a Typedef) { + self.check_generics(&x.generics); + self.check_type(&x.type_); + } + + fn check_opaque_ty(&mut self, x: &'a OpaqueTy) { + x.bounds.iter().for_each(|b| self.check_generic_bound(b)); + self.check_generics(&x.generics); + } + + fn check_constant(&mut self, x: &'a Constant) { + self.check_type(&x.type_); + } + + fn check_static(&mut self, x: &'a Static) { + self.check_type(&x.type_); + } + + fn check_macro(&mut self, _: &'a str) { + // TODO + } + + fn check_proc_macro(&mut self, _: &'a ProcMacro) { + // TODO + } + + fn check_primitive_type(&mut self, _: &'a str) { + // TODO + } + + fn check_generics(&mut self, x: &'a Generics) { + x.params.iter().for_each(|p| self.check_generic_param_def(p)); + x.where_predicates.iter().for_each(|w| self.check_where_predicate(w)); + } + + fn check_type(&mut self, x: &'a Type) { + match x { + Type::ResolvedPath(path) => self.check_path(path), + Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait), + Type::Generic(_) => {} + Type::Primitive(_) => {} + Type::FunctionPointer(fp) => self.check_function_pointer(&**fp), + Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)), + Type::Slice(inner) => self.check_type(&**inner), + Type::Array { type_, len: _ } => self.check_type(&**type_), + Type::ImplTrait(bounds) => bounds.iter().for_each(|b| self.check_generic_bound(b)), + Type::Infer => {} + Type::RawPointer { mutable: _, type_ } => self.check_type(&**type_), + Type::BorrowedRef { lifetime: _, mutable: _, type_ } => self.check_type(&**type_), + Type::QualifiedPath { name: _, args, self_type, trait_ } => { + self.check_generic_args(&**args); + self.check_type(&**self_type); + self.check_path(trait_); + } + } + } + + fn check_fn_decl(&mut self, x: &'a FnDecl) { + x.inputs.iter().for_each(|(_name, ty)| self.check_type(ty)); + if let Some(output) = &x.output { + self.check_type(output); + } + } + + fn check_generic_bound(&mut self, x: &'a GenericBound) { + match x { + GenericBound::TraitBound { trait_, generic_params, modifier: _ } => { + self.check_path(trait_); + generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + GenericBound::Outlives(_) => todo!(), + } + } + + fn check_path(&mut self, x: &'a Path) { + self.add_id(&x.id); // TODO: What kinds are allowed here. + if let Some(args) = &x.args { + self.check_generic_args(&**args); + } + } + + fn check_generic_args(&mut self, x: &'a GenericArgs) { + match x { + GenericArgs::AngleBracketed { args, bindings } => { + args.iter().for_each(|arg| self.check_generic_arg(arg)); + bindings.iter().for_each(|bind| self.check_type_binding(bind)); + } + GenericArgs::Parenthesized { inputs, output } => { + inputs.iter().for_each(|ty| self.check_type(ty)); + if let Some(o) = output { + self.check_type(o); + } + } + } + } + + fn check_generic_param_def(&mut self, gpd: &'a GenericParamDef) { + match &gpd.kind { + rustdoc_json_types::GenericParamDefKind::Lifetime { outlives: _ } => {} + rustdoc_json_types::GenericParamDefKind::Type { bounds, default, synthetic: _ } => { + bounds.iter().for_each(|b| self.check_generic_bound(b)); + if let Some(ty) = default { + self.check_type(ty); + } + } + rustdoc_json_types::GenericParamDefKind::Const { type_, default: _ } => { + self.check_type(type_) + } + } + } + + fn check_generic_arg(&mut self, arg: &'a GenericArg) { + match arg { + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => self.check_type(ty), + GenericArg::Const(c) => self.check_constant(c), + GenericArg::Infer => {} + } + } + + fn check_type_binding(&mut self, bind: &'a TypeBinding) { + self.check_generic_args(&bind.args); + match &bind.binding { + TypeBindingKind::Equality(term) => self.check_term(term), + TypeBindingKind::Constraint(bounds) => { + bounds.iter().for_each(|b| self.check_generic_bound(b)) + } + } + } + + fn check_term(&mut self, term: &'a Term) { + match term { + Term::Type(ty) => self.check_type(ty), + Term::Constant(con) => self.check_constant(con), + } + } + + fn check_where_predicate(&mut self, w: &'a WherePredicate) { + match w { + WherePredicate::BoundPredicate { type_, bounds, generic_params } => { + self.check_type(type_); + bounds.iter().for_each(|b| self.check_generic_bound(b)); + generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + WherePredicate::RegionPredicate { lifetime: _, bounds } => { + bounds.iter().for_each(|b| self.check_generic_bound(b)); + } + WherePredicate::EqPredicate { lhs, rhs } => { + self.check_type(lhs); + self.check_term(rhs); + } + } + } + + fn check_dyn_trait(&mut self, dyn_trait: &'a DynTrait) { + for pt in &dyn_trait.traits { + self.check_path(&pt.trait_); + pt.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + } + + fn check_function_pointer(&mut self, fp: &'a FunctionPointer) { + self.check_fn_decl(&fp.decl); + fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + + // Aux functions + fn add_id(&mut self, id: &'a Id) { + if !self.seen_ids.contains(id) { + self.todo.insert(id); + } + } + + fn add_field_id(&mut self, id: &'a Id) { + let item = &self.krate.index[id]; + if let ItemEnum::StructField(_) = item.inner { + self.add_id(id); + } else { + self.fail(id, "Expecting field"); + } + } + + fn add_mod_id(&mut self, id: &'a Id) { + let item = &self.krate.index[id]; + if let ItemEnum::Module(_) = item.inner { + self.add_id(id); + } else { + self.fail(id, "Expecting module"); + } + } + + fn add_impl_id(&mut self, id: &'a Id) { + let item = &self.krate.index[id]; + if let ItemEnum::StructField(_) = item.inner { + self.add_id(id); + } else { + self.fail(id, "Expecting impl"); + } + } + + fn add_variant_id(&mut self, id: &'a Id) { + let item = &self.krate.index[id]; + if let ItemEnum::StructField(_) = item.inner { + self.add_id(id); + } else { + self.fail(id, "Expecting variant"); + } + } + + /// Add an Id that appeared in a trait + fn add_trait_item_id(&mut self, id: &'a Id) { + let item = &self.krate.index[id]; + if !can_appear_in_mod(&item.inner) { + self.fail(id, "Expecting item that can appear in trait"); + } else { + self.add_id(id); + } + } + + /// Add an Id that appeared in a mod + fn add_mod_item_id(&mut self, id: &'a Id) { + let item = &self.krate.index[id]; + if can_appear_in_mod(&item.inner) { + self.add_id(id); + } else { + self.fail(id, "Expecting item that can appear in trait"); + } + } + + fn fail(&mut self, id: &Id, msg: &str) { + self.errs.push(Error { id: id.clone(), message: msg.to_string() }); + } +} From bb1911db393047382ae040c23598e25984244644 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 24 Aug 2022 19:44:32 +0100 Subject: [PATCH 12/22] jsondoclint: Add `Kind` abstraction --- src/tools/jsondoclint/src/item_kind.rs | 205 +++++++++++++++++++++---- src/tools/jsondoclint/src/validator.rs | 74 +++++---- 2 files changed, 213 insertions(+), 66 deletions(-) diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index 7c6c0b5437928..15866ab6950f3 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -1,29 +1,180 @@ -use rustdoc_json_types::ItemEnum; - -pub(crate) fn can_appear_in_mod(kind: &ItemEnum) -> bool { - match kind { - ItemEnum::Module(_) => true, - ItemEnum::ExternCrate { .. } => true, - ItemEnum::Import(_) => true, - ItemEnum::Union(_) => true, - ItemEnum::Struct(_) => true, - ItemEnum::StructField(_) => false, // Only in structs or variants - ItemEnum::Enum(_) => true, - ItemEnum::Variant(_) => false, // Only in enums - ItemEnum::Function(_) => true, - ItemEnum::Trait(_) => true, - ItemEnum::TraitAlias(_) => true, - ItemEnum::Method(_) => false, // Only in traits - ItemEnum::Impl(_) => true, - ItemEnum::Typedef(_) => true, - ItemEnum::OpaqueTy(_) => todo!("IDK"), // On - ItemEnum::Constant(_) => true, - ItemEnum::Static(_) => true, - ItemEnum::ForeignType => todo!("IDK"), - ItemEnum::Macro(_) => true, - ItemEnum::ProcMacro(_) => true, - ItemEnum::PrimitiveType(_) => todo!("IDK"), - ItemEnum::AssocConst { .. } => false, // Trait Only - ItemEnum::AssocType { .. } => false, // Trait only +use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; + +// We want a univeral way to represent an `ItemEnum` or `ItemKind` + +#[derive(Debug)] +pub(crate) enum Kind { + Module, + ExternCrate, + Import, + Struct, + StructField, + Union, + Enum, + Variant, + Function, + Typedef, + OpaqueTy, + Constant, + Trait, + TraitAlias, + Method, + Impl, + Static, + ForeignType, + Macro, + ProcAttribute, + ProcDerive, + AssocConst, + AssocType, + Primitive, + Keyword, + // Not in ItemKind + ProcMacro, + PrimitiveType, +} + +impl Kind { + pub fn can_appear_in_mod(self) -> bool { + use Kind::*; + match self { + Module => true, + ExternCrate => true, + Import => true, + Union => true, + Struct => true, + Enum => true, + Function => true, + Trait => true, + TraitAlias => true, + Impl => true, + Typedef => true, + Constant => true, + Static => true, + Macro => true, + ProcMacro => true, + + ForeignType => todo!("IDK"), + Keyword => todo!("IDK"), + OpaqueTy => todo!("IDK"), + Primitive => todo!("IDK"), + PrimitiveType => todo!("IDK"), + ProcAttribute => todo!("IDK"), + ProcDerive => todo!("IDK"), + + // Only in traits + AssocConst => false, + AssocType => false, + Method => false, + + StructField => false, // Only in structs or variants + Variant => false, // Only in enums + } + } + + pub fn can_appear_in_trait(self) -> bool { + match self { + Kind::AssocConst => true, + Kind::AssocType => true, + Kind::Method => true, + + Kind::Module => false, + Kind::ExternCrate => false, + Kind::Import => false, + Kind::Struct => false, + Kind::StructField => false, + Kind::Union => false, + Kind::Enum => false, + Kind::Variant => false, + Kind::Function => false, + Kind::Typedef => false, + Kind::OpaqueTy => false, + Kind::Constant => false, + Kind::Trait => false, + Kind::TraitAlias => false, + Kind::Impl => false, + Kind::Static => false, + Kind::ForeignType => false, + Kind::Macro => false, + Kind::ProcAttribute => false, + Kind::ProcDerive => false, + Kind::Primitive => false, + Kind::Keyword => false, + Kind::ProcMacro => false, + Kind::PrimitiveType => false, + } + } + + pub fn is_struct_field(self) -> bool { + matches!(self, Kind::StructField) + } + pub fn is_module(self) -> bool { + matches!(self, Kind::Module) + } + pub fn is_impl(self) -> bool { + matches!(self, Kind::Impl) + } + pub fn is_variant(self) -> bool { + matches!(self, Kind::Variant) + } + + pub fn from_item(i: &Item) -> Self { + use Kind::*; + match i.inner { + ItemEnum::Module(_) => Module, + ItemEnum::Import(_) => Import, + ItemEnum::Union(_) => Union, + ItemEnum::Struct(_) => Struct, + ItemEnum::StructField(_) => StructField, + ItemEnum::Enum(_) => Enum, + ItemEnum::Variant(_) => Variant, + ItemEnum::Function(_) => Function, + ItemEnum::Trait(_) => Trait, + ItemEnum::TraitAlias(_) => TraitAlias, + ItemEnum::Method(_) => Method, + ItemEnum::Impl(_) => Impl, + ItemEnum::Typedef(_) => Typedef, + ItemEnum::OpaqueTy(_) => OpaqueTy, + ItemEnum::Constant(_) => Constant, + ItemEnum::Static(_) => Static, + ItemEnum::Macro(_) => Macro, + ItemEnum::ProcMacro(_) => ProcMacro, + ItemEnum::PrimitiveType(_) => PrimitiveType, + ItemEnum::ForeignType => ForeignType, + ItemEnum::ExternCrate { .. } => ExternCrate, + ItemEnum::AssocConst { .. } => AssocConst, + ItemEnum::AssocType { .. } => AssocType, + } + } + + pub fn from_summary(s: &ItemSummary) -> Self { + use Kind::*; + match s.kind { + ItemKind::AssocConst => AssocConst, + ItemKind::AssocType => AssocType, + ItemKind::Constant => Constant, + ItemKind::Enum => Enum, + ItemKind::ExternCrate => ExternCrate, + ItemKind::ForeignType => ForeignType, + ItemKind::Function => Function, + ItemKind::Impl => Impl, + ItemKind::Import => Import, + ItemKind::Keyword => Keyword, + ItemKind::Macro => Macro, + ItemKind::Method => Method, + ItemKind::Module => Module, + ItemKind::OpaqueTy => OpaqueTy, + ItemKind::Primitive => Primitive, + ItemKind::ProcAttribute => ProcAttribute, + ItemKind::ProcDerive => ProcDerive, + ItemKind::Static => Static, + ItemKind::Struct => Struct, + ItemKind::StructField => StructField, + ItemKind::Trait => Trait, + ItemKind::TraitAlias => TraitAlias, + ItemKind::Typedef => Typedef, + ItemKind::Union => Union, + ItemKind::Variant => Variant, + } } } diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 2bb63bc3a44e5..b0e12479f92c6 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -8,7 +8,7 @@ use rustdoc_json_types::{ TypeBindingKind, Typedef, Union, Variant, WherePredicate, }; -use crate::{item_kind::can_appear_in_mod, Error}; +use crate::{item_kind::Kind, Error}; #[derive(Debug)] pub struct Validator<'a> { @@ -329,63 +329,59 @@ impl<'a> Validator<'a> { } } - fn add_field_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::StructField(_) = item.inner { - self.add_id(id); + fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) { + if let Some(kind) = self.kind_of(id) { + if valid(kind) { + self.add_id(id); + } else { + self.fail_expecting(id, expected); + } } else { - self.fail(id, "Expecting field"); + self.fail(id, "Not found") } } - fn add_mod_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::Module(_) = item.inner { - self.add_id(id); - } else { - self.fail(id, "Expecting module"); - } + fn add_field_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_struct_field, "StructField"); } + fn add_mod_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_module, "Module"); + } fn add_impl_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::StructField(_) = item.inner { - self.add_id(id); - } else { - self.fail(id, "Expecting impl"); - } + self.add_id_checked(id, Kind::is_impl, "Impl"); } fn add_variant_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::StructField(_) = item.inner { - self.add_id(id); - } else { - self.fail(id, "Expecting variant"); - } + self.add_id_checked(id, Kind::is_variant, "Variant"); } /// Add an Id that appeared in a trait fn add_trait_item_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if !can_appear_in_mod(&item.inner) { - self.fail(id, "Expecting item that can appear in trait"); - } else { - self.add_id(id); - } + self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item"); } /// Add an Id that appeared in a mod fn add_mod_item_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if can_appear_in_mod(&item.inner) { - self.add_id(id); - } else { - self.fail(id, "Expecting item that can appear in trait"); - } + self.add_id_checked(id, Kind::can_appear_in_mod, "Module inner item") + } + + fn fail_expecting(&mut self, id: &Id, expected: &str) { + let kind = self.kind_of(id).unwrap(); // We know it has a kind, as it's wrong. + self.fail(id, format!("Expected {expected} but found {kind:?}")); } - fn fail(&mut self, id: &Id, msg: &str) { - self.errs.push(Error { id: id.clone(), message: msg.to_string() }); + fn fail(&mut self, id: &Id, message: impl Into) { + self.errs.push(Error { id: id.clone(), message: message.into() }); + } + + fn kind_of(&mut self, id: &Id) -> Option { + if let Some(item) = self.krate.index.get(id) { + Some(Kind::from_item(item)) + } else if let Some(summary) = self.krate.paths.get(id) { + Some(Kind::from_summary(summary)) + } else { + None + } } } From 5f1bc6fc5e362c5955f6a06a7cf21e62b97c86c7 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 24 Aug 2022 20:09:37 +0100 Subject: [PATCH 13/22] jsondocck: Better errors --- src/tools/jsondoclint/src/item_kind.rs | 19 +++--- src/tools/jsondoclint/src/main.rs | 13 +++- src/tools/jsondoclint/src/validator.rs | 83 ++++++++++++++++---------- 3 files changed, 70 insertions(+), 45 deletions(-) diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index 15866ab6950f3..f4153245e0b7f 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -31,7 +31,6 @@ pub(crate) enum Kind { Keyword, // Not in ItemKind ProcMacro, - PrimitiveType, } impl Kind { @@ -54,13 +53,13 @@ impl Kind { Macro => true, ProcMacro => true, - ForeignType => todo!("IDK"), - Keyword => todo!("IDK"), - OpaqueTy => todo!("IDK"), - Primitive => todo!("IDK"), - PrimitiveType => todo!("IDK"), - ProcAttribute => todo!("IDK"), - ProcDerive => todo!("IDK"), + // FIXME(adotinthevoid): I'm not sure if these are corrent + ForeignType => false, + Keyword => false, + OpaqueTy => false, + Primitive => false, + ProcAttribute => false, + ProcDerive => false, // Only in traits AssocConst => false, @@ -101,7 +100,6 @@ impl Kind { Kind::Primitive => false, Kind::Keyword => false, Kind::ProcMacro => false, - Kind::PrimitiveType => false, } } @@ -139,7 +137,8 @@ impl Kind { ItemEnum::Static(_) => Static, ItemEnum::Macro(_) => Macro, ItemEnum::ProcMacro(_) => ProcMacro, - ItemEnum::PrimitiveType(_) => PrimitiveType, + // https://github.com/rust-lang/rust/issues/100961 + ItemEnum::PrimitiveType(_) => Primitive, ItemEnum::ForeignType => ForeignType, ItemEnum::ExternCrate { .. } => ExternCrate, ItemEnum::AssocConst { .. } => AssocConst, diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index b98601f7d89f9..4df8fbc29a2bb 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -9,10 +9,16 @@ mod validator; #[derive(Debug)] struct Error { - message: String, + kind: ErrorKind, id: Id, } +#[derive(Debug)] +enum ErrorKind { + NotFound, + Custom(String), +} + fn main() -> Result<()> { let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?; let contents = fs::read_to_string(path)?; @@ -24,7 +30,10 @@ fn main() -> Result<()> { if !validator.errs.is_empty() { for err in validator.errs { - eprintln!("`{}`: `{}`", err.id.0, err.message); + match err.kind { + ErrorKind::NotFound => eprintln!("{}: Not Found", err.id.0), + ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg), + } } bail!("Errors validating json"); } diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index b0e12479f92c6..06b114f6c2fe6 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -8,13 +8,14 @@ use rustdoc_json_types::{ TypeBindingKind, Typedef, Union, Variant, WherePredicate, }; -use crate::{item_kind::Kind, Error}; +use crate::{item_kind::Kind, Error, ErrorKind}; #[derive(Debug)] pub struct Validator<'a> { pub(crate) errs: Vec, krate: &'a Crate, seen_ids: HashSet<&'a Id>, + missing_ids: HashSet<&'a Id>, todo: HashSet<&'a Id>, } @@ -29,7 +30,13 @@ fn set_remove(set: &mut HashSet) -> Option { impl<'a> Validator<'a> { pub fn new(krate: &'a Crate) -> Self { - Self { krate, errs: Vec::new(), seen_ids: HashSet::new(), todo: HashSet::new() } + Self { + krate, + errs: Vec::new(), + seen_ids: HashSet::new(), + todo: HashSet::new(), + missing_ids: HashSet::new(), + } } pub fn check_crate(&mut self) { @@ -42,32 +49,39 @@ impl<'a> Validator<'a> { } fn check_item(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - match &item.inner { - ItemEnum::Import(x) => self.check_import(x), - ItemEnum::Union(x) => self.check_union(x), - ItemEnum::Struct(x) => self.check_struct(x), - ItemEnum::StructField(x) => self.check_struct_field(x), - ItemEnum::Enum(x) => self.check_enum(x), - ItemEnum::Variant(x) => self.check_variant(x), - ItemEnum::Function(x) => self.check_function(x), - ItemEnum::Trait(x) => self.check_trait(x), - ItemEnum::TraitAlias(x) => self.check_trait_alias(x), - ItemEnum::Method(x) => self.check_method(x), - ItemEnum::Impl(x) => self.check_impl(x), - ItemEnum::Typedef(x) => self.check_typedef(x), - ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x), - ItemEnum::Constant(x) => self.check_constant(x), - ItemEnum::Static(x) => self.check_static(x), - ItemEnum::ForeignType => todo!(), - ItemEnum::Macro(x) => self.check_macro(x), - ItemEnum::ProcMacro(x) => self.check_proc_macro(x), - ItemEnum::PrimitiveType(x) => self.check_primitive_type(x), - ItemEnum::Module(x) => self.check_module(x), - - ItemEnum::ExternCrate { .. } => todo!(), - ItemEnum::AssocConst { .. } => todo!(), - ItemEnum::AssocType { .. } => todo!(), + if let Some(item) = &self.krate.index.get(id) { + match &item.inner { + ItemEnum::Import(x) => self.check_import(x), + ItemEnum::Union(x) => self.check_union(x), + ItemEnum::Struct(x) => self.check_struct(x), + ItemEnum::StructField(x) => self.check_struct_field(x), + ItemEnum::Enum(x) => self.check_enum(x), + ItemEnum::Variant(x) => self.check_variant(x), + ItemEnum::Function(x) => self.check_function(x), + ItemEnum::Trait(x) => self.check_trait(x), + ItemEnum::TraitAlias(x) => self.check_trait_alias(x), + ItemEnum::Method(x) => self.check_method(x), + ItemEnum::Impl(x) => self.check_impl(x), + ItemEnum::Typedef(x) => self.check_typedef(x), + ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x), + ItemEnum::Constant(x) => self.check_constant(x), + ItemEnum::Static(x) => self.check_static(x), + ItemEnum::ForeignType => todo!(), + ItemEnum::Macro(x) => self.check_macro(x), + ItemEnum::ProcMacro(x) => self.check_proc_macro(x), + ItemEnum::PrimitiveType(x) => self.check_primitive_type(x), + ItemEnum::Module(x) => self.check_module(x), + // FIXME: Why don't these have their own structs? + ItemEnum::ExternCrate { .. } => {} + ItemEnum::AssocConst { type_, default: _ } => self.check_type(type_), + ItemEnum::AssocType { generics, bounds, default } => { + self.check_generics(generics); + bounds.iter().for_each(|b| self.check_generic_bound(b)); + if let Some(ty) = default { + self.check_type(ty); + } + } + } } } @@ -226,7 +240,7 @@ impl<'a> Validator<'a> { self.check_path(trait_); generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } - GenericBound::Outlives(_) => todo!(), + GenericBound::Outlives(_) => {} } } @@ -337,7 +351,10 @@ impl<'a> Validator<'a> { self.fail_expecting(id, expected); } } else { - self.fail(id, "Not found") + if !self.missing_ids.contains(id) { + self.missing_ids.insert(id); + self.fail(id, ErrorKind::NotFound) + } } } @@ -368,11 +385,11 @@ impl<'a> Validator<'a> { fn fail_expecting(&mut self, id: &Id, expected: &str) { let kind = self.kind_of(id).unwrap(); // We know it has a kind, as it's wrong. - self.fail(id, format!("Expected {expected} but found {kind:?}")); + self.fail(id, ErrorKind::Custom(format!("Expected {expected} but found {kind:?}"))); } - fn fail(&mut self, id: &Id, message: impl Into) { - self.errs.push(Error { id: id.clone(), message: message.into() }); + fn fail(&mut self, id: &Id, kind: ErrorKind) { + self.errs.push(Error { id: id.clone(), kind }); } fn kind_of(&mut self, id: &Id) -> Option { From 41d35a97f9f33e265de53b8f04abe307d7616641 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 24 Aug 2022 23:18:53 +0100 Subject: [PATCH 14/22] jsondocck: Find path to Id's not in index --- src/tools/jsondoclint/src/json_find.rs | 74 ++++++++++++++++++++++++++ src/tools/jsondoclint/src/main.rs | 28 ++++++++-- 2 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 src/tools/jsondoclint/src/json_find.rs diff --git a/src/tools/jsondoclint/src/json_find.rs b/src/tools/jsondoclint/src/json_find.rs new file mode 100644 index 0000000000000..95ea8866609d0 --- /dev/null +++ b/src/tools/jsondoclint/src/json_find.rs @@ -0,0 +1,74 @@ +use std::fmt::Write; + +use serde_json::Value; + +#[derive(Debug, Clone)] +pub enum SelectorPart { + Field(String), + Index(usize), +} + +pub type Selector = Vec; + +pub fn to_jsonpath(sel: &Selector) -> String { + let mut s = String::from("$"); + for part in sel { + match part { + SelectorPart::Field(name) => { + if is_jsonpath_safe(name) { + write!(&mut s, ".{}", name).unwrap(); + } else { + // This is probably wrong in edge cases, but all Id's are + // just ascii alphanumerics, `-` `_`, and `:` + write!(&mut s, "[{name:?}]").unwrap(); + } + } + SelectorPart::Index(idx) => write!(&mut s, "[{idx}]").unwrap(), + } + } + s +} + +fn is_jsonpath_safe(s: &str) -> bool { + s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') +} + +pub fn find_selector(haystack: &Value, needle: &Value) -> Vec { + let mut result = Vec::new(); + let mut sel = Selector::new(); + find_selector_recursive(haystack, needle, &mut result, &mut sel); + result +} + +fn find_selector_recursive( + haystack: &Value, + needle: &Value, + result: &mut Vec, + pos: &mut Selector, +) { + if needle == haystack { + result.push(pos.clone()); + // Haystack cant both contain needle and be needle + } else { + match haystack { + Value::Null => {} + Value::Bool(_) => {} + Value::Number(_) => {} + Value::String(_) => {} + Value::Array(arr) => { + for (idx, subhaystack) in arr.iter().enumerate() { + pos.push(SelectorPart::Index(idx)); + find_selector_recursive(subhaystack, needle, result, pos); + pos.pop().unwrap(); + } + } + Value::Object(obj) => { + for (key, subhaystack) in obj { + pos.push(SelectorPart::Field(key.clone())); + find_selector_recursive(subhaystack, needle, result, pos); + pos.pop().unwrap(); + } + } + } + } +} diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index 4df8fbc29a2bb..1d02482421ba4 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -3,8 +3,10 @@ use std::env; use anyhow::{anyhow, bail, Result}; use fs_err as fs; use rustdoc_json_types::{Crate, Id, FORMAT_VERSION}; +use serde_json::Value; pub(crate) mod item_kind; +mod json_find; mod validator; #[derive(Debug)] @@ -21,8 +23,10 @@ enum ErrorKind { fn main() -> Result<()> { let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?; - let contents = fs::read_to_string(path)?; + let contents = fs::read_to_string(&path)?; let krate: Crate = serde_json::from_str(&contents)?; + // TODO: Only load if nessessary. + let krate_json: Value = serde_json::from_str(&contents)?; assert_eq!(krate.format_version, FORMAT_VERSION); let mut validator = validator::Validator::new(&krate); @@ -31,11 +35,29 @@ fn main() -> Result<()> { if !validator.errs.is_empty() { for err in validator.errs { match err.kind { - ErrorKind::NotFound => eprintln!("{}: Not Found", err.id.0), + ErrorKind::NotFound => { + let sels = + json_find::find_selector(&krate_json, &Value::String(err.id.0.clone())); + match &sels[..] { + [] => unreachable!( + "id must be in crate, or it wouldn't be reported as not found" + ), + [sel] => eprintln!( + "{} not in index or paths, but refered to at '{}'", + err.id.0, + json_find::to_jsonpath(&sel) + ), + [sel, ..] => eprintln!( + "{} not in index or paths, but refered to at '{}' and more", + err.id.0, + json_find::to_jsonpath(&sel) + ), + } + } ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg), } } - bail!("Errors validating json"); + bail!("Errors validating json {path}"); } Ok(()) From c98c7cbfa5e9d9f414101f17abd4639b9541c9e7 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 30 Aug 2022 14:16:38 +0100 Subject: [PATCH 15/22] Primitives can appear in modules. --- src/tools/jsondoclint/src/item_kind.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index f4153245e0b7f..f46da20fd5814 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -52,12 +52,12 @@ impl Kind { Static => true, Macro => true, ProcMacro => true, + Primitive => true, // FIXME(adotinthevoid): I'm not sure if these are corrent ForeignType => false, Keyword => false, OpaqueTy => false, - Primitive => false, ProcAttribute => false, ProcDerive => false, From 5956b56ab251b9aafecd2ad6f431c42e069b3058 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 14 Sep 2022 14:47:25 +0100 Subject: [PATCH 16/22] jsondoclint: Document validator --- src/tools/jsondoclint/src/item_kind.rs | 3 +- src/tools/jsondoclint/src/main.rs | 4 +-- src/tools/jsondoclint/src/validator.rs | 44 +++++++++++++++----------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index f46da20fd5814..b3e88a9081383 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -1,7 +1,6 @@ use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; -// We want a univeral way to represent an `ItemEnum` or `ItemKind` - +/// A univeral way to represent an [`ItemEnum`] or [`ItemKind`] #[derive(Debug)] pub(crate) enum Kind { Module, diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index 1d02482421ba4..70d7a82a57605 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -25,8 +25,6 @@ fn main() -> Result<()> { let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?; let contents = fs::read_to_string(&path)?; let krate: Crate = serde_json::from_str(&contents)?; - // TODO: Only load if nessessary. - let krate_json: Value = serde_json::from_str(&contents)?; assert_eq!(krate.format_version, FORMAT_VERSION); let mut validator = validator::Validator::new(&krate); @@ -36,6 +34,8 @@ fn main() -> Result<()> { for err in validator.errs { match err.kind { ErrorKind::NotFound => { + let krate_json: Value = serde_json::from_str(&contents)?; + let sels = json_find::find_selector(&krate_json, &Value::String(err.id.0.clone())); match &sels[..] { diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 06b114f6c2fe6..efe2c165b6c4e 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -10,22 +10,24 @@ use rustdoc_json_types::{ use crate::{item_kind::Kind, Error, ErrorKind}; +/// The Validator walks over the JSON tree, and ensures it is well formed. +/// It is made of several parts. +/// +/// - `check_*`: These take a type from [`rustdoc_json_types`], and check that +/// it is well formed. This involves calling `check_*` functions on +/// fields of that item, and `add_*` functions on [`Id`]s. +/// - `add_*`: These add an [`Id`] to the worklist, after validating it to check if +/// the `Id` is a kind expected in this suituation. #[derive(Debug)] pub struct Validator<'a> { pub(crate) errs: Vec, krate: &'a Crate, + /// Worklist of Ids to check. + todo: HashSet<&'a Id>, + /// Ids that have already been visited, so don't need to be checked again. seen_ids: HashSet<&'a Id>, + /// Ids that have already been reported missing. missing_ids: HashSet<&'a Id>, - todo: HashSet<&'a Id>, -} - -fn set_remove(set: &mut HashSet) -> Option { - if let Some(id) = set.iter().next() { - let id = id.clone(); - set.take(&id) - } else { - None - } } impl<'a> Validator<'a> { @@ -82,6 +84,8 @@ impl<'a> Validator<'a> { } } } + } else { + assert!(self.krate.paths.contains_key(id)); } } @@ -336,17 +340,12 @@ impl<'a> Validator<'a> { fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } - // Aux functions - fn add_id(&mut self, id: &'a Id) { - if !self.seen_ids.contains(id) { - self.todo.insert(id); - } - } - fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) { if let Some(kind) = self.kind_of(id) { if valid(kind) { - self.add_id(id); + if !self.seen_ids.contains(id) { + self.todo.insert(id); + } } else { self.fail_expecting(id, expected); } @@ -402,3 +401,12 @@ impl<'a> Validator<'a> { } } } + +fn set_remove(set: &mut HashSet) -> Option { + if let Some(id) = set.iter().next() { + let id = id.clone(); + set.take(&id) + } else { + None + } +} From 393792da8d8a931643baf855369df0a009acdb19 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 14 Sep 2022 14:51:18 +0100 Subject: [PATCH 17/22] Remove check_missing_items.py --- src/etc/check_missing_items.py | 202 --------------------------- src/tools/compiletest/src/runtest.rs | 9 -- triagebot.toml | 2 - 3 files changed, 213 deletions(-) delete mode 100644 src/etc/check_missing_items.py diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py deleted file mode 100644 index 0026c4cbdca2c..0000000000000 --- a/src/etc/check_missing_items.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python - -# This test ensures that every ID in the produced json actually resolves to an item either in -# `index` or `paths`. It DOES NOT check that the structure of the produced json is actually in -# any way correct, for example an empty map would pass. - -# FIXME: Better error output - -import sys -import json - -crate = json.load(open(sys.argv[1], encoding="utf-8")) - - -def get_local_item(item_id): - if item_id in crate["index"]: - return crate["index"][item_id] - print("Missing local ID:", item_id) - sys.exit(1) - - -# local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have -# to be in `paths` -def valid_id(item_id): - return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"] - - -def check_generics(generics): - for param in generics["params"]: - check_generic_param(param) - for where_predicate in generics["where_predicates"]: - if "bound_predicate" in where_predicate: - pred = where_predicate["bound_predicate"] - check_type(pred["type"]) - for bound in pred["bounds"]: - check_generic_bound(bound) - elif "region_predicate" in where_predicate: - pred = where_predicate["region_predicate"] - for bound in pred["bounds"]: - check_generic_bound(bound) - elif "eq_predicate" in where_predicate: - pred = where_predicate["eq_predicate"] - check_type(pred["rhs"]) - check_type(pred["lhs"]) - - -def check_generic_param(param): - if "type" in param["kind"]: - ty = param["kind"]["type"] - if ty["default"]: - check_type(ty["default"]) - for bound in ty["bounds"]: - check_generic_bound(bound) - elif "const" in param["kind"]: - check_type(param["kind"]["const"]) - - -def check_generic_bound(bound): - if "trait_bound" in bound: - for param in bound["trait_bound"]["generic_params"]: - check_generic_param(param) - check_path(bound["trait_bound"]["trait"]) - - -def check_decl(decl): - for (_name, ty) in decl["inputs"]: - check_type(ty) - if decl["output"]: - check_type(decl["output"]) - -def check_path(path): - args = path["args"] - if args: - if "angle_bracketed" in args: - for arg in args["angle_bracketed"]["args"]: - if "type" in arg: - check_type(arg["type"]) - elif "const" in arg: - check_type(arg["const"]["type"]) - for binding in args["angle_bracketed"]["bindings"]: - if "equality" in binding["binding"]: - term = binding["binding"]["equality"] - if "type" in term: check_type(term["type"]) - elif "const" in term: check_type(term["const"]) - elif "constraint" in binding["binding"]: - for bound in binding["binding"]["constraint"]: - check_generic_bound(bound) - elif "parenthesized" in args: - for input_ty in args["parenthesized"]["inputs"]: - check_type(input_ty) - if args["parenthesized"]["output"]: - check_type(args["parenthesized"]["output"]) - - if path["id"] in crate["index"]: - work_list.add(path["id"]) - elif path["id"] not in crate["paths"]: - print("Id not in index or paths:", path["id"]) - sys.exit(1) - -def check_type(ty): - if ty["kind"] == "resolved_path": - check_path(ty["inner"]) - elif ty["kind"] == "tuple": - for ty in ty["inner"]: - check_type(ty) - elif ty["kind"] == "slice": - check_type(ty["inner"]) - elif ty["kind"] == "impl_trait": - for bound in ty["inner"]: - check_generic_bound(bound) - elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"): - check_type(ty["inner"]["type"]) - elif ty["kind"] == "function_pointer": - for param in ty["inner"]["generic_params"]: - check_generic_param(param) - check_decl(ty["inner"]["decl"]) - elif ty["kind"] == "qualified_path": - check_type(ty["inner"]["self_type"]) - check_path(ty["inner"]["trait"]) - - -work_list = set([crate["root"]]) -visited = work_list.copy() - -while work_list: - current = work_list.pop() - visited.add(current) - item = get_local_item(current) - # check intradoc links - for (_name, link) in item["links"].items(): - if not valid_id(link): - print("Intra-doc link contains invalid ID:", link) - - # check all fields that reference types such as generics as well as nested items - # (modules, structs, traits, and enums) - if item["kind"] == "module": - work_list |= set(item["inner"]["items"]) - visited - elif item["kind"] == "struct": - check_generics(item["inner"]["generics"]) - work_list |= set(item["inner"]["impls"]) - visited - if "tuple" in item["inner"]["kind"]: - work_list |= set(filter(None, item["inner"]["kind"]["tuple"])) - visited - elif "plain" in item["inner"]["kind"]: - work_list |= set(item["inner"]["kind"]["plain"]["fields"]) - visited - elif item["kind"] == "struct_field": - check_type(item["inner"]) - elif item["kind"] == "enum": - check_generics(item["inner"]["generics"]) - work_list |= ( - set(item["inner"]["variants"]) | set(item["inner"]["impls"]) - ) - visited - elif item["kind"] == "variant": - if item["inner"]["variant_kind"] == "tuple": - for field_id in filter(None, item["inner"]["variant_inner"]): - work_list.add(field_id) - elif item["inner"]["variant_kind"] == "struct": - work_list |= set(item["inner"]["variant_inner"]["fields"]) - visited - elif item["kind"] in ("function", "method"): - check_generics(item["inner"]["generics"]) - check_decl(item["inner"]["decl"]) - elif item["kind"] in ("static", "constant", "assoc_const"): - check_type(item["inner"]["type"]) - elif item["kind"] == "typedef": - check_type(item["inner"]["type"]) - check_generics(item["inner"]["generics"]) - elif item["kind"] == "opaque_ty": - check_generics(item["inner"]["generics"]) - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - elif item["kind"] == "trait_alias": - check_generics(item["inner"]["params"]) - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - elif item["kind"] == "trait": - check_generics(item["inner"]["generics"]) - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - work_list |= ( - set(item["inner"]["items"]) | set(item["inner"]["implementations"]) - ) - visited - elif item["kind"] == "impl": - check_generics(item["inner"]["generics"]) - if item["inner"]["trait"]: - check_path(item["inner"]["trait"]) - if item["inner"]["blanket_impl"]: - check_type(item["inner"]["blanket_impl"]) - check_type(item["inner"]["for"]) - for assoc_item in item["inner"]["items"]: - if not valid_id(assoc_item): - print("Impl block referenced a missing ID:", assoc_item) - sys.exit(1) - elif item["kind"] == "assoc_type": - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - if item["inner"]["default"]: - check_type(item["inner"]["default"]) - elif item["kind"] == "import": - if item["inner"]["id"]: - inner_id = item["inner"]["id"] - assert valid_id(inner_id) - if inner_id in crate["index"] and inner_id not in visited: - work_list.add(inner_id) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 9cbb6b7c393bd..8f289876f7307 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2563,15 +2563,6 @@ impl<'test> TestCx<'test> { let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); json_out.set_extension("json"); - let res = self.cmd2procres( - Command::new(&self.config.python) - .arg(root.join("src/etc/check_missing_items.py")) - .arg(&json_out), - ); - - if !res.status.success() { - self.fatal_proc_rec("check_missing_items failed!", &res); - } let res = self.cmd2procres( Command::new(self.config.jsondoclint_path.as_ref().unwrap()).arg(&json_out), diff --git a/triagebot.toml b/triagebot.toml index 11caedbb9597a..12a55fda7ef4d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -130,7 +130,6 @@ trigger_files = [ # Internal tooling "src/etc/htmldocck.py", - "src/etc/check_missing_items.py", "src/tools/jsondocck", "src/tools/jsondoclint", "src/tools/rustdoc-gui", @@ -143,7 +142,6 @@ exclude_labels = [ [autolabel."A-rustdoc-json"] trigger_files = [ - "src/etc/check_missing_items.py", "src/librustdoc/json/", "src/rustdoc-json-types", "src/test/rustdoc-json", From 24c751b2bad4a3cb6020462d3769f735762ef5b3 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 14 Sep 2022 15:08:56 +0100 Subject: [PATCH 18/22] Rustdoc-Json: Add test for extern_types --- src/test/rustdoc-json/type/extern.rs | 10 ++++++++++ src/tools/jsondoclint/src/item_kind.rs | 2 +- src/tools/jsondoclint/src/validator.rs | 9 ++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc-json/type/extern.rs diff --git a/src/test/rustdoc-json/type/extern.rs b/src/test/rustdoc-json/type/extern.rs new file mode 100644 index 0000000000000..d287d5ebec543 --- /dev/null +++ b/src/test/rustdoc-json/type/extern.rs @@ -0,0 +1,10 @@ +#![feature(extern_types)] + +extern { + /// No inner information + pub type Foo; +} + +// @is "$.index[*][?(@.docs=='No inner information')].name" '"Foo"' +// @is "$.index[*][?(@.docs=='No inner information')].kind" '"foreign_type"' +// @!has "$.index[*][?(@.docs=='No inner information')].inner" diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index b3e88a9081383..65d7143d13385 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -52,9 +52,9 @@ impl Kind { Macro => true, ProcMacro => true, Primitive => true, + ForeignType => true, // FIXME(adotinthevoid): I'm not sure if these are corrent - ForeignType => false, Keyword => false, OpaqueTy => false, ProcAttribute => false, diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index efe2c165b6c4e..d7bf6fe9e3ca4 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -68,7 +68,7 @@ impl<'a> Validator<'a> { ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x), ItemEnum::Constant(x) => self.check_constant(x), ItemEnum::Static(x) => self.check_static(x), - ItemEnum::ForeignType => todo!(), + ItemEnum::ForeignType => {} // nop ItemEnum::Macro(x) => self.check_macro(x), ItemEnum::ProcMacro(x) => self.check_proc_macro(x), ItemEnum::PrimitiveType(x) => self.check_primitive_type(x), @@ -340,6 +340,13 @@ impl<'a> Validator<'a> { fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } + // TODO: Remove + fn add_id(&mut self, id: &'a Id) { + if !self.seen_ids.contains(id) { + self.todo.insert(id); + } + } + fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) { if let Some(kind) = self.kind_of(id) { if valid(kind) { From 6e21a28ddaf31bf5c6c78d83d051214d2212e803 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 14 Sep 2022 15:31:45 +0100 Subject: [PATCH 19/22] jsondoclint: More precise `Path` checks --- src/tools/jsondoclint/src/item_kind.rs | 6 +++++ src/tools/jsondoclint/src/validator.rs | 37 ++++++++++++++++---------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index 65d7143d13385..ad8e96a0bd81d 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -114,6 +114,12 @@ impl Kind { pub fn is_variant(self) -> bool { matches!(self, Kind::Variant) } + pub fn is_trait(self) -> bool { + matches!(self, Kind::Trait) + } + pub fn is_struct_enum_union(self) -> bool { + matches!(self, Kind::Struct | Kind::Enum | Kind::Union) + } pub fn from_item(i: &Item) -> Self { use Kind::*; diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index d7bf6fe9e3ca4..3226ea4f334ef 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -30,6 +30,11 @@ pub struct Validator<'a> { missing_ids: HashSet<&'a Id>, } +enum PathKind { + Trait, + StructEnumUnion, +} + impl<'a> Validator<'a> { pub fn new(krate: &'a Crate) -> Self { Self { @@ -165,7 +170,7 @@ impl<'a> Validator<'a> { fn check_impl(&mut self, x: &'a Impl) { self.check_generics(&x.generics); if let Some(path) = &x.trait_ { - self.check_path(path); // TODO: Check is trait. + self.check_path(path, PathKind::Trait); } self.check_type(&x.for_); x.items.iter().for_each(|i| self.add_trait_item_id(i)); @@ -211,7 +216,7 @@ impl<'a> Validator<'a> { fn check_type(&mut self, x: &'a Type) { match x { - Type::ResolvedPath(path) => self.check_path(path), + Type::ResolvedPath(path) => self.check_path(path, PathKind::StructEnumUnion), Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait), Type::Generic(_) => {} Type::Primitive(_) => {} @@ -226,7 +231,7 @@ impl<'a> Validator<'a> { Type::QualifiedPath { name: _, args, self_type, trait_ } => { self.check_generic_args(&**args); self.check_type(&**self_type); - self.check_path(trait_); + self.check_path(trait_, PathKind::Trait); } } } @@ -241,15 +246,18 @@ impl<'a> Validator<'a> { fn check_generic_bound(&mut self, x: &'a GenericBound) { match x { GenericBound::TraitBound { trait_, generic_params, modifier: _ } => { - self.check_path(trait_); + self.check_path(trait_, PathKind::Trait); generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } GenericBound::Outlives(_) => {} } } - fn check_path(&mut self, x: &'a Path) { - self.add_id(&x.id); // TODO: What kinds are allowed here. + fn check_path(&mut self, x: &'a Path, kind: PathKind) { + match kind { + PathKind::Trait => self.add_trait_id(&x.id), + PathKind::StructEnumUnion => self.add_struct_enum_union_id(&x.id), + } if let Some(args) = &x.args { self.check_generic_args(&**args); } @@ -330,7 +338,7 @@ impl<'a> Validator<'a> { fn check_dyn_trait(&mut self, dyn_trait: &'a DynTrait) { for pt in &dyn_trait.traits { - self.check_path(&pt.trait_); + self.check_path(&pt.trait_, PathKind::Trait); pt.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } } @@ -340,13 +348,6 @@ impl<'a> Validator<'a> { fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } - // TODO: Remove - fn add_id(&mut self, id: &'a Id) { - if !self.seen_ids.contains(id) { - self.todo.insert(id); - } - } - fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) { if let Some(kind) = self.kind_of(id) { if valid(kind) { @@ -379,6 +380,14 @@ impl<'a> Validator<'a> { self.add_id_checked(id, Kind::is_variant, "Variant"); } + fn add_trait_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_trait, "Trait"); + } + + fn add_struct_enum_union_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_struct_enum_union, "Struct or Enum or Union"); + } + /// Add an Id that appeared in a trait fn add_trait_item_id(&mut self, id: &'a Id) { self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item"); From f69a6c2a8018ac69db62446996e815893b70dfcd Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 14 Sep 2022 15:41:54 +0100 Subject: [PATCH 20/22] jsondoclint: Fix TODO's --- src/tools/jsondoclint/src/validator.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 3226ea4f334ef..a0e77127dc2ca 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -63,7 +63,7 @@ impl<'a> Validator<'a> { ItemEnum::Struct(x) => self.check_struct(x), ItemEnum::StructField(x) => self.check_struct_field(x), ItemEnum::Enum(x) => self.check_enum(x), - ItemEnum::Variant(x) => self.check_variant(x), + ItemEnum::Variant(x) => self.check_variant(x, id), ItemEnum::Function(x) => self.check_function(x), ItemEnum::Trait(x) => self.check_trait(x), ItemEnum::TraitAlias(x) => self.check_trait_alias(x), @@ -135,9 +135,23 @@ impl<'a> Validator<'a> { x.impls.iter().for_each(|i| self.add_impl_id(i)); } - fn check_variant(&mut self, x: &'a Variant) { + fn check_variant(&mut self, x: &'a Variant, id: &'a Id) { match x { - Variant::Plain(_discriminant) => {} // TODO: Check discriminant value parses + Variant::Plain(discr) => { + if let Some(discr) = discr { + if let (Err(_), Err(_)) = + (discr.value.parse::(), discr.value.parse::()) + { + self.fail( + id, + ErrorKind::Custom(format!( + "Failed to parse discriminant value `{}`", + discr.value + )), + ); + } + } + } Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)), Variant::Struct { fields, fields_stripped: _ } => { fields.iter().for_each(|f| self.add_field_id(f)) @@ -198,15 +212,15 @@ impl<'a> Validator<'a> { } fn check_macro(&mut self, _: &'a str) { - // TODO + // nop } fn check_proc_macro(&mut self, _: &'a ProcMacro) { - // TODO + // nop } fn check_primitive_type(&mut self, _: &'a str) { - // TODO + // nop } fn check_generics(&mut self, x: &'a Generics) { From 8df181d26b5c79e7e84d68c5695e9eb4365367c9 Mon Sep 17 00:00:00 2001 From: Chris Wailes Date: Tue, 13 Sep 2022 16:13:43 -0700 Subject: [PATCH 21/22] Improve handing of env vars during bootstrap process This CL modifies the handing of env vars during the bootstrap process in two ways: 1. Replaces '-' characters with '_' characters in target names to increase compatibility with different shells 2. Passes Stage0 snapshot compiler related env vars to early invocations of Cargo --- src/bootstrap/bootstrap.py | 15 +++++++++++---- src/bootstrap/builder.rs | 13 +++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index cc08ae5f99f0e..19ace2cdf5761 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -732,9 +732,19 @@ def build_bootstrap(self, color): (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" + # Export Stage0 snapshot compiler related env variables + build_section = f"target.{self.build}" + host_triple_sanitized = self.build.replace("-", "_") + var_data = { + "CC": "cc", "CXX": "cxx", "LD": "linker", "AR": "ar", "RANLIB": "ranlib" + } + for var_name, toml_key in var_data.items(): + toml_val = self.get_toml(toml_key, build_section) + if toml_val != None: + env[f"{var_name}_{host_triple_sanitized}"] = toml_val + # preserve existing RUSTFLAGS env.setdefault("RUSTFLAGS", "") - build_section = "target.{}".format(self.build) target_features = [] if self.get_toml("crt-static", build_section) == "true": target_features += ["+crt-static"] @@ -742,9 +752,6 @@ def build_bootstrap(self, color): target_features += ["-crt-static"] if target_features: env["RUSTFLAGS"] += " -C target-feature=" + (",".join(target_features)) - target_linker = self.get_toml("linker", build_section) - if target_linker is not None: - env["RUSTFLAGS"] += " -C linker=" + target_linker env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes" env["RUSTFLAGS"] += " -Wsemicolon_in_expressions_from_macros" if self.get_toml("deny-warnings", "rust") != "false": diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 14e8ebd6876b4..b654db6dbe9a3 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1940,25 +1940,26 @@ impl<'a> Builder<'a> { _ => s.display().to_string(), } }; + let triple_underscored = target.triple.replace("-", "_"); let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{}", target.triple), &cc); + cargo.env(format!("CC_{}", triple_underscored), &cc); let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" "); - cargo.env(format!("CFLAGS_{}", target.triple), &cflags); + cargo.env(format!("CFLAGS_{}", triple_underscored), &cflags); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); cargo - .env(format!("AR_{}", target.triple), ar) - .env(format!("RANLIB_{}", target.triple), ranlib); + .env(format!("AR_{}", triple_underscored), ar) + .env(format!("RANLIB_{}", triple_underscored), ranlib); } if let Ok(cxx) = self.cxx(target) { let cxx = ccacheify(&cxx); let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" "); cargo - .env(format!("CXX_{}", target.triple), &cxx) - .env(format!("CXXFLAGS_{}", target.triple), cxxflags); + .env(format!("CXX_{}", triple_underscored), &cxx) + .env(format!("CXXFLAGS_{}", triple_underscored), cxxflags); } } From 4cdf264e6fe58325dcedb2f571cbac4aed095eb7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 9 Sep 2022 15:34:11 +0000 Subject: [PATCH 22/22] cache collect_trait_impl_trait_tys --- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 3 ++- compiler/rustc_query_impl/src/on_disk_cache.rs | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9b1fedd0b533c..6bdf5a023b6c3 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -102,7 +102,7 @@ macro_rules! arena_types { [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, - [] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap>, + [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap>, ]); ) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0fe22a26cd503..5cc2b7984d709 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -164,7 +164,8 @@ rustc_queries! { query collect_trait_impl_trait_tys(key: DefId) -> Result<&'tcx FxHashMap>, ErrorGuaranteed> { - desc { "better description please" } + desc { "compare an impl and trait method signature, inferring any hidden `impl Trait` types in the process" } + cache_on_disk_if { key.is_local() } separate_provide_extern } diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 5ef95911f562d..0e93f3ce1d646 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -798,6 +798,12 @@ impl<'a, 'tcx> Decodable> for &'tcx FxHashSet } } +impl<'a, 'tcx> Decodable> for &'tcx FxHashMap> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx IndexVec> {