Auto merge of #75534 - Aaron1011:feature/new-future-breakage, r=pnkfelix
Implement rustc side of report-future-incompat cc https://github.com/rust-lang/rust/issues/71249 This is an alternative to `@pnkfelix's` initial implementation in https://github.com/pnkfelix/rust/commits/prototype-rustc-side-of-report-future-incompat (mainly because I started working before seeing that branch 😄 ). My approach outputs the entire original `Diagnostic`, in a way that is compatible with incremental compilation. This is not yet integrated with compiletest, but can be used manually by passing `-Z emit-future-incompat-report` to `rustc`. Several changes are made to support this feature: * The `librustc_session/lint` module is moved to a new crate `librustc_lint_defs` (name bikesheddable). This allows accessing lint definitions from `librustc_errors`. * The `Lint` struct is extended with an `Option<FutureBreakage>`. When present, it indicates that we should display a lint in the future-compat report. `FutureBreakage` contains additional information that we may want to display in the report (currently, a `date` field indicating when the crate will stop compiling). * A new variant `rustc_error::Level::Allow` is added. This is used when constructing a diagnostic for a future-breakage lint that is marked as allowed (via `#[allow]` or `--cap-lints`). This allows us to capture any future-breakage diagnostics in one place, while still discarding them before they are passed to the `Emitter`. * `DiagnosticId::Lint` is extended with a `has_future_breakage` field, indicating whether or not the `Lint` has future breakage information (and should therefore show up in the report). * `Session` is given access to the `LintStore` via a new `SessionLintStore` trait (since `librustc_session` cannot directly reference `LintStore` without a cyclic dependency). We use this to turn a string `DiagnosticId::Lint` back into a `Lint`, to retrieve the `FutureBreakage` data. Currently, `FutureBreakage.date` is always set to `None`. However, this could potentially be interpreted by Cargo in the future. I've enabled the future-breakage report for the `ARRAY_INTO_ITER` lint, which can be used to test out this PR. The intent is to use the field to allow Cargo to determine the date of future breakage (as described in [RFC 2834](https://github.com/rust-lang/rfcs/blob/master/text/2834-cargo-report-future-incompat.md)) without needing to parse the diagnostic itself. cc `@pnkfelix`
This commit is contained in:
commit
b202532608
28 changed files with 539 additions and 123 deletions
14
Cargo.lock
14
Cargo.lock
|
@ -3638,6 +3638,7 @@ dependencies = [
|
||||||
"annotate-snippets 0.8.0",
|
"annotate-snippets 0.8.0",
|
||||||
"atty",
|
"atty",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
|
"rustc_lint_defs",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
@ -3830,6 +3831,18 @@ dependencies = [
|
||||||
"unicode-security",
|
"unicode-security",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_lint_defs"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_ast",
|
||||||
|
"rustc_data_structures",
|
||||||
|
"rustc_macros",
|
||||||
|
"rustc_serialize",
|
||||||
|
"rustc_span",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_llvm"
|
name = "rustc_llvm"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -4112,6 +4125,7 @@ dependencies = [
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
"rustc_fs_util",
|
"rustc_fs_util",
|
||||||
|
"rustc_lint_defs",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
|
@ -308,8 +308,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
E0726,
|
E0726,
|
||||||
"implicit elided lifetime not allowed here"
|
"implicit elided lifetime not allowed here"
|
||||||
);
|
);
|
||||||
rustc_session::lint::add_elided_lifetime_in_path_suggestion(
|
rustc_errors::add_elided_lifetime_in_path_suggestion(
|
||||||
&self.sess,
|
&self.sess.source_map(),
|
||||||
&mut err,
|
&mut err,
|
||||||
expected_lifetimes,
|
expected_lifetimes,
|
||||||
path_span,
|
path_span,
|
||||||
|
|
|
@ -13,6 +13,7 @@ rustc_serialize = { path = "../rustc_serialize" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
|
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||||
unicode-width = "0.1.4"
|
unicode-width = "0.1.4"
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
termcolor = "1.0"
|
termcolor = "1.0"
|
||||||
|
|
|
@ -72,6 +72,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType {
|
||||||
Level::Help => AnnotationType::Help,
|
Level::Help => AnnotationType::Help,
|
||||||
// FIXME(#59346): Not sure how to map these two levels
|
// FIXME(#59346): Not sure how to map these two levels
|
||||||
Level::Cancelled | Level::FailureNote => AnnotationType::Error,
|
Level::Cancelled | Level::FailureNote => AnnotationType::Error,
|
||||||
|
Level::Allow => panic!("Should not call with Allow"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +144,8 @@ impl AnnotateSnippetEmitterWriter {
|
||||||
title: Some(Annotation {
|
title: Some(Annotation {
|
||||||
label: Some(&message),
|
label: Some(&message),
|
||||||
id: code.as_ref().map(|c| match c {
|
id: code.as_ref().map(|c| match c {
|
||||||
DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val.as_str(),
|
DiagnosticId::Error(val)
|
||||||
|
| DiagnosticId::Lint { name: val, has_future_breakage: _ } => val.as_str(),
|
||||||
}),
|
}),
|
||||||
annotation_type: annotation_type_for_level(*level),
|
annotation_type: annotation_type_for_level(*level),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::snippet::Style;
|
use crate::snippet::Style;
|
||||||
use crate::Applicability;
|
|
||||||
use crate::CodeSuggestion;
|
use crate::CodeSuggestion;
|
||||||
use crate::Level;
|
use crate::Level;
|
||||||
use crate::Substitution;
|
use crate::Substitution;
|
||||||
use crate::SubstitutionPart;
|
use crate::SubstitutionPart;
|
||||||
use crate::SuggestionStyle;
|
use crate::SuggestionStyle;
|
||||||
|
use rustc_lint_defs::Applicability;
|
||||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ pub struct Diagnostic {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||||
pub enum DiagnosticId {
|
pub enum DiagnosticId {
|
||||||
Error(String),
|
Error(String),
|
||||||
Lint(String),
|
Lint { name: String, has_future_breakage: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example a note attached to an error.
|
/// For example a note attached to an error.
|
||||||
|
@ -107,7 +107,14 @@ impl Diagnostic {
|
||||||
match self.level {
|
match self.level {
|
||||||
Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true,
|
Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true,
|
||||||
|
|
||||||
Level::Warning | Level::Note | Level::Help | Level::Cancelled => false,
|
Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_future_breakage(&self) -> bool {
|
||||||
|
match self.code {
|
||||||
|
Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{Applicability, Handler, Level, StashKey};
|
|
||||||
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString};
|
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString};
|
||||||
|
use crate::{Handler, Level, StashKey};
|
||||||
|
use rustc_lint_defs::Applicability;
|
||||||
|
|
||||||
use rustc_span::{MultiSpan, Span};
|
use rustc_span::{MultiSpan, Span};
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
|
@ -9,14 +9,15 @@
|
||||||
|
|
||||||
use Destination::*;
|
use Destination::*;
|
||||||
|
|
||||||
|
use rustc_lint_defs::FutureBreakage;
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::{MultiSpan, SourceFile, Span};
|
use rustc_span::{MultiSpan, SourceFile, Span};
|
||||||
|
|
||||||
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
|
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
|
||||||
use crate::styled_buffer::StyledBuffer;
|
use crate::styled_buffer::StyledBuffer;
|
||||||
use crate::{
|
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle};
|
||||||
pluralize, CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle,
|
|
||||||
};
|
use rustc_lint_defs::pluralize;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
@ -192,6 +193,8 @@ pub trait Emitter {
|
||||||
/// other formats can, and will, simply ignore it.
|
/// other formats can, and will, simply ignore it.
|
||||||
fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}
|
fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}
|
||||||
|
|
||||||
|
fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {}
|
||||||
|
|
||||||
/// Checks if should show explanations about "rustc --explain"
|
/// Checks if should show explanations about "rustc --explain"
|
||||||
fn should_show_explain(&self) -> bool {
|
fn should_show_explain(&self) -> bool {
|
||||||
true
|
true
|
||||||
|
|
|
@ -13,8 +13,9 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||||
|
|
||||||
use crate::emitter::{Emitter, HumanReadableErrorType};
|
use crate::emitter::{Emitter, HumanReadableErrorType};
|
||||||
use crate::registry::Registry;
|
use crate::registry::Registry;
|
||||||
use crate::{Applicability, DiagnosticId};
|
use crate::DiagnosticId;
|
||||||
use crate::{CodeSuggestion, SubDiagnostic};
|
use crate::{CodeSuggestion, SubDiagnostic};
|
||||||
|
use rustc_lint_defs::{Applicability, FutureBreakage};
|
||||||
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_span::hygiene::ExpnData;
|
use rustc_span::hygiene::ExpnData;
|
||||||
|
@ -131,6 +132,31 @@ impl Emitter for JsonEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_future_breakage_report(&mut self, diags: Vec<(FutureBreakage, crate::Diagnostic)>) {
|
||||||
|
let data: Vec<FutureBreakageItem> = diags
|
||||||
|
.into_iter()
|
||||||
|
.map(|(breakage, mut diag)| {
|
||||||
|
if diag.level == crate::Level::Allow {
|
||||||
|
diag.level = crate::Level::Warning;
|
||||||
|
}
|
||||||
|
FutureBreakageItem {
|
||||||
|
future_breakage_date: breakage.date,
|
||||||
|
diagnostic: Diagnostic::from_errors_diagnostic(&diag, self),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let report = FutureIncompatReport { future_incompat_report: data };
|
||||||
|
let result = if self.pretty {
|
||||||
|
writeln!(&mut self.dst, "{}", as_pretty_json(&report))
|
||||||
|
} else {
|
||||||
|
writeln!(&mut self.dst, "{}", as_json(&report))
|
||||||
|
}
|
||||||
|
.and_then(|_| self.dst.flush());
|
||||||
|
if let Err(e) = result {
|
||||||
|
panic!("failed to print future breakage report: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
|
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
|
||||||
Some(&self.sm)
|
Some(&self.sm)
|
||||||
}
|
}
|
||||||
|
@ -223,6 +249,17 @@ struct ArtifactNotification<'a> {
|
||||||
emit: &'a str,
|
emit: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Encodable)]
|
||||||
|
struct FutureBreakageItem {
|
||||||
|
future_breakage_date: Option<&'static str>,
|
||||||
|
diagnostic: Diagnostic,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encodable)]
|
||||||
|
struct FutureIncompatReport {
|
||||||
|
future_incompat_report: Vec<FutureBreakageItem>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Diagnostic {
|
impl Diagnostic {
|
||||||
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
|
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
|
||||||
let sugg = diag.suggestions.iter().map(|sugg| Diagnostic {
|
let sugg = diag.suggestions.iter().map(|sugg| Diagnostic {
|
||||||
|
@ -432,7 +469,7 @@ impl DiagnosticCode {
|
||||||
s.map(|s| {
|
s.map(|s| {
|
||||||
let s = match s {
|
let s = match s {
|
||||||
DiagnosticId::Error(s) => s,
|
DiagnosticId::Error(s) => s,
|
||||||
DiagnosticId::Lint(s) => s,
|
DiagnosticId::Lint { name, has_future_breakage: _ } => name,
|
||||||
};
|
};
|
||||||
let je_result =
|
let je_result =
|
||||||
je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap();
|
je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap();
|
||||||
|
|
|
@ -21,6 +21,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||||
use rustc_data_structures::stable_hasher::StableHasher;
|
use rustc_data_structures::stable_hasher::StableHasher;
|
||||||
use rustc_data_structures::sync::{self, Lock, Lrc};
|
use rustc_data_structures::sync::{self, Lock, Lrc};
|
||||||
use rustc_data_structures::AtomicRef;
|
use rustc_data_structures::AtomicRef;
|
||||||
|
use rustc_lint_defs::FutureBreakage;
|
||||||
|
pub use rustc_lint_defs::{pluralize, Applicability};
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::{Loc, MultiSpan, Span};
|
use rustc_span::{Loc, MultiSpan, Span};
|
||||||
|
|
||||||
|
@ -49,30 +51,6 @@ pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
|
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
|
||||||
|
|
||||||
/// Indicates the confidence in the correctness of a suggestion.
|
|
||||||
///
|
|
||||||
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
|
|
||||||
/// to determine whether it should be automatically applied or if the user should be consulted
|
|
||||||
/// before applying the suggestion.
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
|
|
||||||
pub enum Applicability {
|
|
||||||
/// The suggestion is definitely what the user intended. This suggestion should be
|
|
||||||
/// automatically applied.
|
|
||||||
MachineApplicable,
|
|
||||||
|
|
||||||
/// The suggestion may be what the user intended, but it is uncertain. The suggestion should
|
|
||||||
/// result in valid Rust code if it is applied.
|
|
||||||
MaybeIncorrect,
|
|
||||||
|
|
||||||
/// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion
|
|
||||||
/// cannot be applied automatically because it will not result in valid Rust code. The user
|
|
||||||
/// will need to fill in the placeholders.
|
|
||||||
HasPlaceholders,
|
|
||||||
|
|
||||||
/// The applicability of the suggestion is unknown.
|
|
||||||
Unspecified,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
|
||||||
pub enum SuggestionStyle {
|
pub enum SuggestionStyle {
|
||||||
/// Hide the suggested code when displaying this suggestion inline.
|
/// Hide the suggested code when displaying this suggestion inline.
|
||||||
|
@ -321,6 +299,8 @@ struct HandlerInner {
|
||||||
|
|
||||||
/// The warning count, used for a recap upon finishing
|
/// The warning count, used for a recap upon finishing
|
||||||
deduplicated_warn_count: usize,
|
deduplicated_warn_count: usize,
|
||||||
|
|
||||||
|
future_breakage_diagnostics: Vec<Diagnostic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A key denoting where from a diagnostic was stashed.
|
/// A key denoting where from a diagnostic was stashed.
|
||||||
|
@ -434,6 +414,7 @@ impl Handler {
|
||||||
emitted_diagnostic_codes: Default::default(),
|
emitted_diagnostic_codes: Default::default(),
|
||||||
emitted_diagnostics: Default::default(),
|
emitted_diagnostics: Default::default(),
|
||||||
stashed_diagnostics: Default::default(),
|
stashed_diagnostics: Default::default(),
|
||||||
|
future_breakage_diagnostics: Vec::new(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -503,6 +484,17 @@ impl Handler {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
|
||||||
|
pub fn struct_span_allow(
|
||||||
|
&self,
|
||||||
|
span: impl Into<MultiSpan>,
|
||||||
|
msg: &str,
|
||||||
|
) -> DiagnosticBuilder<'_> {
|
||||||
|
let mut result = self.struct_allow(msg);
|
||||||
|
result.set_span(span);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
|
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
|
||||||
/// Also include a code.
|
/// Also include a code.
|
||||||
pub fn struct_span_warn_with_code(
|
pub fn struct_span_warn_with_code(
|
||||||
|
@ -525,6 +517,11 @@ impl Handler {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construct a builder at the `Allow` level with the `msg`.
|
||||||
|
pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> {
|
||||||
|
DiagnosticBuilder::new(self, Level::Allow, msg)
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a builder at the `Error` level at the given `span` and with the `msg`.
|
/// Construct a builder at the `Error` level at the given `span` and with the `msg`.
|
||||||
pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
|
pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
|
||||||
let mut result = self.struct_err(msg);
|
let mut result = self.struct_err(msg);
|
||||||
|
@ -693,6 +690,10 @@ impl Handler {
|
||||||
self.inner.borrow_mut().print_error_count(registry)
|
self.inner.borrow_mut().print_error_count(registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
|
||||||
|
std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn abort_if_errors(&self) {
|
pub fn abort_if_errors(&self) {
|
||||||
self.inner.borrow_mut().abort_if_errors()
|
self.inner.borrow_mut().abort_if_errors()
|
||||||
}
|
}
|
||||||
|
@ -723,6 +724,10 @@ impl Handler {
|
||||||
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
|
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn emit_future_breakage_report(&self, diags: Vec<(FutureBreakage, Diagnostic)>) {
|
||||||
|
self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
|
pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
|
||||||
self.inner.borrow_mut().delay_as_bug(diagnostic)
|
self.inner.borrow_mut().delay_as_bug(diagnostic)
|
||||||
}
|
}
|
||||||
|
@ -748,12 +753,23 @@ impl HandlerInner {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if diagnostic.has_future_breakage() {
|
||||||
|
self.future_breakage_diagnostics.push(diagnostic.clone());
|
||||||
|
}
|
||||||
|
|
||||||
if diagnostic.level == Warning && !self.flags.can_emit_warnings {
|
if diagnostic.level == Warning && !self.flags.can_emit_warnings {
|
||||||
|
if diagnostic.has_future_breakage() {
|
||||||
|
(*TRACK_DIAGNOSTICS)(diagnostic);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*TRACK_DIAGNOSTICS)(diagnostic);
|
(*TRACK_DIAGNOSTICS)(diagnostic);
|
||||||
|
|
||||||
|
if diagnostic.level == Allow {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ref code) = diagnostic.code {
|
if let Some(ref code) = diagnostic.code {
|
||||||
self.emitted_diagnostic_codes.insert(code.clone());
|
self.emitted_diagnostic_codes.insert(code.clone());
|
||||||
}
|
}
|
||||||
|
@ -992,6 +1008,7 @@ pub enum Level {
|
||||||
Help,
|
Help,
|
||||||
Cancelled,
|
Cancelled,
|
||||||
FailureNote,
|
FailureNote,
|
||||||
|
Allow,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
impl fmt::Display for Level {
|
||||||
|
@ -1017,7 +1034,7 @@ impl Level {
|
||||||
spec.set_fg(Some(Color::Cyan)).set_intense(true);
|
spec.set_fg(Some(Color::Cyan)).set_intense(true);
|
||||||
}
|
}
|
||||||
FailureNote => {}
|
FailureNote => {}
|
||||||
Cancelled => unreachable!(),
|
Allow | Cancelled => unreachable!(),
|
||||||
}
|
}
|
||||||
spec
|
spec
|
||||||
}
|
}
|
||||||
|
@ -1031,6 +1048,7 @@ impl Level {
|
||||||
Help => "help",
|
Help => "help",
|
||||||
FailureNote => "failure-note",
|
FailureNote => "failure-note",
|
||||||
Cancelled => panic!("Shouldn't call on cancelled error"),
|
Cancelled => panic!("Shouldn't call on cancelled error"),
|
||||||
|
Allow => panic!("Shouldn't call on allowed error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,11 +1057,46 @@ impl Level {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
pub fn add_elided_lifetime_in_path_suggestion(
|
||||||
macro_rules! pluralize {
|
source_map: &SourceMap,
|
||||||
($x:expr) => {
|
db: &mut DiagnosticBuilder<'_>,
|
||||||
if $x != 1 { "s" } else { "" }
|
n: usize,
|
||||||
|
path_span: Span,
|
||||||
|
incl_angl_brckt: bool,
|
||||||
|
insertion_span: Span,
|
||||||
|
anon_lts: String,
|
||||||
|
) {
|
||||||
|
let (replace_span, suggestion) = if incl_angl_brckt {
|
||||||
|
(insertion_span, anon_lts)
|
||||||
|
} else {
|
||||||
|
// When possible, prefer a suggestion that replaces the whole
|
||||||
|
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
||||||
|
// at a point (which makes for an ugly/confusing label)
|
||||||
|
if let Ok(snippet) = source_map.span_to_snippet(path_span) {
|
||||||
|
// But our spans can get out of whack due to macros; if the place we think
|
||||||
|
// we want to insert `'_` isn't even within the path expression's span, we
|
||||||
|
// should bail out of making any suggestion rather than panicking on a
|
||||||
|
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
||||||
|
// FIXME: can we do better?
|
||||||
|
if insertion_span.lo().0 < path_span.lo().0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
||||||
|
if insertion_index > snippet.len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let (before, after) = snippet.split_at(insertion_index);
|
||||||
|
(path_span, format!("{}{}{}", before, anon_lts, after))
|
||||||
|
} else {
|
||||||
|
(insertion_span, anon_lts)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
db.span_suggestion(
|
||||||
|
replace_span,
|
||||||
|
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
|
||||||
|
suggestion,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Useful type to use with `Result<>` indicate that an error has already
|
// Useful type to use with `Result<>` indicate that an error has already
|
||||||
|
|
|
@ -286,7 +286,10 @@ pub fn register_plugins<'a>(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok((krate, Lrc::new(lint_store)))
|
let lint_store = Lrc::new(lint_store);
|
||||||
|
sess.init_lint_store(lint_store.clone());
|
||||||
|
|
||||||
|
Ok((krate, lint_store))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) {
|
fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) {
|
||||||
|
|
|
@ -477,6 +477,7 @@ fn test_debugging_options_tracking_hash() {
|
||||||
untracked!(dump_mir_dir, String::from("abc"));
|
untracked!(dump_mir_dir, String::from("abc"));
|
||||||
untracked!(dump_mir_exclude_pass_number, true);
|
untracked!(dump_mir_exclude_pass_number, true);
|
||||||
untracked!(dump_mir_graphviz, true);
|
untracked!(dump_mir_graphviz, true);
|
||||||
|
untracked!(emit_future_incompat_report, true);
|
||||||
untracked!(emit_stack_sizes, true);
|
untracked!(emit_stack_sizes, true);
|
||||||
untracked!(hir_stats, true);
|
untracked!(hir_stats, true);
|
||||||
untracked!(identify_regions, true);
|
untracked!(identify_regions, true);
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
||||||
use rustc_session::lint::FutureIncompatibleInfo;
|
use rustc_session::lint::FutureBreakage;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -38,6 +38,9 @@ declare_lint! {
|
||||||
@future_incompatible = FutureIncompatibleInfo {
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>",
|
reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>",
|
||||||
edition: None,
|
edition: None,
|
||||||
|
future_breakage: Some(FutureBreakage {
|
||||||
|
date: None
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ use rustc_middle::lint::LintDiagnosticBuilder;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, Subst};
|
use rustc_middle::ty::subst::{GenericArgKind, Subst};
|
||||||
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
|
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
|
||||||
use rustc_session::lint::FutureIncompatibleInfo;
|
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use rustc_ast as ast;
|
||||||
use rustc_ast::util::lev_distance::find_best_match_for_name;
|
use rustc_ast::util::lev_distance::find_best_match_for_name;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync;
|
use rustc_data_structures::sync;
|
||||||
use rustc_errors::{struct_span_err, Applicability};
|
use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::def_id::{CrateNum, DefId};
|
use rustc_hir::def_id::{CrateNum, DefId};
|
||||||
|
@ -33,9 +33,10 @@ use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
|
use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
|
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
|
||||||
use rustc_session::lint::{add_elided_lifetime_in_path_suggestion, BuiltinLintDiagnostics};
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
|
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
use rustc_session::SessionLintStore;
|
||||||
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
|
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
|
||||||
use rustc_target::abi::LayoutOf;
|
use rustc_target::abi::LayoutOf;
|
||||||
|
|
||||||
|
@ -69,6 +70,20 @@ pub struct LintStore {
|
||||||
lint_groups: FxHashMap<&'static str, LintGroup>,
|
lint_groups: FxHashMap<&'static str, LintGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SessionLintStore for LintStore {
|
||||||
|
fn name_to_lint(&self, lint_name: &str) -> LintId {
|
||||||
|
let lints = self
|
||||||
|
.find_lints(lint_name)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to find lint with name `{}`", lint_name));
|
||||||
|
|
||||||
|
if let &[lint] = lints.as_slice() {
|
||||||
|
return lint;
|
||||||
|
} else {
|
||||||
|
panic!("Found mutliple lints with name `{}`: {:?}", lint_name, lints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The target of the `by_name` map, which accounts for renaming/deprecation.
|
/// The target of the `by_name` map, which accounts for renaming/deprecation.
|
||||||
enum TargetLint {
|
enum TargetLint {
|
||||||
/// A direct lint target
|
/// A direct lint target
|
||||||
|
@ -543,7 +558,7 @@ pub trait LintContext: Sized {
|
||||||
anon_lts,
|
anon_lts,
|
||||||
) => {
|
) => {
|
||||||
add_elided_lifetime_in_path_suggestion(
|
add_elided_lifetime_in_path_suggestion(
|
||||||
sess,
|
sess.source_map(),
|
||||||
&mut db,
|
&mut db,
|
||||||
n,
|
n,
|
||||||
path_span,
|
path_span,
|
||||||
|
|
13
compiler/rustc_lint_defs/Cargo.toml
Normal file
13
compiler/rustc_lint_defs/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
authors = ["The Rust Project Developers"]
|
||||||
|
name = "rustc_lint_defs"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = { package = "tracing", version = "0.1" }
|
||||||
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
|
rustc_span = { path = "../rustc_span" }
|
||||||
|
rustc_serialize = { path = "../rustc_serialize" }
|
||||||
|
rustc_macros = { path = "../rustc_macros" }
|
|
@ -4,7 +4,6 @@
|
||||||
//! compiler code, rather than using their own custom pass. Those
|
//! compiler code, rather than using their own custom pass. Those
|
||||||
//! lints are all available in `rustc_lint::builtin`.
|
//! lints are all available in `rustc_lint::builtin`.
|
||||||
|
|
||||||
use crate::lint::FutureIncompatibleInfo;
|
|
||||||
use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
|
use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
|
@ -1,12 +1,45 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rustc_macros;
|
||||||
|
|
||||||
pub use self::Level::*;
|
pub use self::Level::*;
|
||||||
use rustc_ast::node_id::{NodeId, NodeMap};
|
use rustc_ast::node_id::{NodeId, NodeMap};
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
||||||
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
|
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
|
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
|
||||||
|
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pluralize {
|
||||||
|
($x:expr) => {
|
||||||
|
if $x != 1 { "s" } else { "" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates the confidence in the correctness of a suggestion.
|
||||||
|
///
|
||||||
|
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
|
||||||
|
/// to determine whether it should be automatically applied or if the user should be consulted
|
||||||
|
/// before applying the suggestion.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
|
||||||
|
pub enum Applicability {
|
||||||
|
/// The suggestion is definitely what the user intended. This suggestion should be
|
||||||
|
/// automatically applied.
|
||||||
|
MachineApplicable,
|
||||||
|
|
||||||
|
/// The suggestion may be what the user intended, but it is uncertain. The suggestion should
|
||||||
|
/// result in valid Rust code if it is applied.
|
||||||
|
MaybeIncorrect,
|
||||||
|
|
||||||
|
/// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion
|
||||||
|
/// cannot be applied automatically because it will not result in valid Rust code. The user
|
||||||
|
/// will need to fill in the placeholders.
|
||||||
|
HasPlaceholders,
|
||||||
|
|
||||||
|
/// The applicability of the suggestion is unknown.
|
||||||
|
Unspecified,
|
||||||
|
}
|
||||||
|
|
||||||
/// Setting for how to handle a lint.
|
/// Setting for how to handle a lint.
|
||||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||||
pub enum Level {
|
pub enum Level {
|
||||||
|
@ -106,6 +139,21 @@ pub struct FutureIncompatibleInfo {
|
||||||
/// If this is an edition fixing lint, the edition in which
|
/// If this is an edition fixing lint, the edition in which
|
||||||
/// this lint becomes obsolete
|
/// this lint becomes obsolete
|
||||||
pub edition: Option<Edition>,
|
pub edition: Option<Edition>,
|
||||||
|
/// Information about a future breakage, which will
|
||||||
|
/// be emitted in JSON messages to be displayed by Cargo
|
||||||
|
/// for upstream deps
|
||||||
|
pub future_breakage: Option<FutureBreakage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct FutureBreakage {
|
||||||
|
pub date: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FutureIncompatibleInfo {
|
||||||
|
pub const fn default_fields_for_macro() -> Self {
|
||||||
|
FutureIncompatibleInfo { reference: "", edition: None, future_breakage: None }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lint {
|
impl Lint {
|
||||||
|
@ -331,31 +379,34 @@ macro_rules! declare_lint {
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
||||||
$(@future_incompatible = $fi:expr;)?
|
|
||||||
$(@feature_gate = $gate:expr;)?
|
$(@feature_gate = $gate:expr;)?
|
||||||
|
$(@future_incompatible = FutureIncompatibleInfo { $($field:ident : $val:expr),* $(,)* }; )?
|
||||||
$($v:ident),*) => (
|
$($v:ident),*) => (
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
|
$vis static $NAME: &$crate::Lint = &$crate::Lint {
|
||||||
name: stringify!($NAME),
|
name: stringify!($NAME),
|
||||||
default_level: $crate::lint::$Level,
|
default_level: $crate::$Level,
|
||||||
desc: $desc,
|
desc: $desc,
|
||||||
edition_lint_opts: None,
|
edition_lint_opts: None,
|
||||||
is_plugin: false,
|
is_plugin: false,
|
||||||
$($v: true,)*
|
$($v: true,)*
|
||||||
$(future_incompatible: Some($fi),)*
|
|
||||||
$(feature_gate: Some($gate),)*
|
$(feature_gate: Some($gate),)*
|
||||||
..$crate::lint::Lint::default_fields_for_macro()
|
$(future_incompatible: Some($crate::FutureIncompatibleInfo {
|
||||||
|
$($field: $val,)*
|
||||||
|
..$crate::FutureIncompatibleInfo::default_fields_for_macro()
|
||||||
|
}),)*
|
||||||
|
..$crate::Lint::default_fields_for_macro()
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
||||||
$lint_edition: expr => $edition_level: ident
|
$lint_edition: expr => $edition_level: ident
|
||||||
) => (
|
) => (
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
|
$vis static $NAME: &$crate::Lint = &$crate::Lint {
|
||||||
name: stringify!($NAME),
|
name: stringify!($NAME),
|
||||||
default_level: $crate::lint::$Level,
|
default_level: $crate::$Level,
|
||||||
desc: $desc,
|
desc: $desc,
|
||||||
edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)),
|
edition_lint_opts: Some(($lint_edition, $crate::Level::$edition_level)),
|
||||||
report_in_external_macro: false,
|
report_in_external_macro: false,
|
||||||
is_plugin: false,
|
is_plugin: false,
|
||||||
};
|
};
|
||||||
|
@ -380,9 +431,9 @@ macro_rules! declare_tool_lint {
|
||||||
$external:expr
|
$external:expr
|
||||||
) => (
|
) => (
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
|
$vis static $NAME: &$crate::Lint = &$crate::Lint {
|
||||||
name: &concat!(stringify!($tool), "::", stringify!($NAME)),
|
name: &concat!(stringify!($tool), "::", stringify!($NAME)),
|
||||||
default_level: $crate::lint::$Level,
|
default_level: $crate::$Level,
|
||||||
desc: $desc,
|
desc: $desc,
|
||||||
edition_lint_opts: None,
|
edition_lint_opts: None,
|
||||||
report_in_external_macro: $external,
|
report_in_external_macro: $external,
|
||||||
|
@ -413,11 +464,11 @@ pub trait LintPass {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_lint_pass {
|
macro_rules! impl_lint_pass {
|
||||||
($ty:ty => [$($lint:expr),* $(,)?]) => {
|
($ty:ty => [$($lint:expr),* $(,)?]) => {
|
||||||
impl $crate::lint::LintPass for $ty {
|
impl $crate::LintPass for $ty {
|
||||||
fn name(&self) -> &'static str { stringify!($ty) }
|
fn name(&self) -> &'static str { stringify!($ty) }
|
||||||
}
|
}
|
||||||
impl $ty {
|
impl $ty {
|
||||||
pub fn get_lints() -> $crate::lint::LintArray { $crate::lint_array!($($lint),*) }
|
pub fn get_lints() -> $crate::LintArray { $crate::lint_array!($($lint),*) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -431,45 +482,3 @@ macro_rules! declare_lint_pass {
|
||||||
$crate::impl_lint_pass!($name => [$($lint),*]);
|
$crate::impl_lint_pass!($name => [$($lint),*]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_elided_lifetime_in_path_suggestion(
|
|
||||||
sess: &crate::Session,
|
|
||||||
db: &mut DiagnosticBuilder<'_>,
|
|
||||||
n: usize,
|
|
||||||
path_span: Span,
|
|
||||||
incl_angl_brckt: bool,
|
|
||||||
insertion_span: Span,
|
|
||||||
anon_lts: String,
|
|
||||||
) {
|
|
||||||
let (replace_span, suggestion) = if incl_angl_brckt {
|
|
||||||
(insertion_span, anon_lts)
|
|
||||||
} else {
|
|
||||||
// When possible, prefer a suggestion that replaces the whole
|
|
||||||
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
|
||||||
// at a point (which makes for an ugly/confusing label)
|
|
||||||
if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
|
|
||||||
// But our spans can get out of whack due to macros; if the place we think
|
|
||||||
// we want to insert `'_` isn't even within the path expression's span, we
|
|
||||||
// should bail out of making any suggestion rather than panicking on a
|
|
||||||
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
|
||||||
// FIXME: can we do better?
|
|
||||||
if insertion_span.lo().0 < path_span.lo().0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
|
||||||
if insertion_index > snippet.len() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let (before, after) = snippet.split_at(insertion_index);
|
|
||||||
(path_span, format!("{}{}{}", before, anon_lts, after))
|
|
||||||
} else {
|
|
||||||
(insertion_span, anon_lts)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
db.span_suggestion(
|
|
||||||
replace_span,
|
|
||||||
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
|
|
||||||
suggestion,
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -225,20 +225,31 @@ pub fn struct_lint_level<'s, 'd>(
|
||||||
span: Option<MultiSpan>,
|
span: Option<MultiSpan>,
|
||||||
decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
|
decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
|
||||||
) {
|
) {
|
||||||
|
// Check for future incompatibility lints and issue a stronger warning.
|
||||||
|
let lint_id = LintId::of(lint);
|
||||||
|
let future_incompatible = lint.future_incompatible;
|
||||||
|
|
||||||
|
let has_future_breakage =
|
||||||
|
future_incompatible.map_or(false, |incompat| incompat.future_breakage.is_some());
|
||||||
|
|
||||||
let mut err = match (level, span) {
|
let mut err = match (level, span) {
|
||||||
(Level::Allow, _) => {
|
(Level::Allow, span) => {
|
||||||
|
if has_future_breakage {
|
||||||
|
if let Some(span) = span {
|
||||||
|
sess.struct_span_allow(span, "")
|
||||||
|
} else {
|
||||||
|
sess.struct_allow("")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
(Level::Warn, Some(span)) => sess.struct_span_warn(span, ""),
|
(Level::Warn, Some(span)) => sess.struct_span_warn(span, ""),
|
||||||
(Level::Warn, None) => sess.struct_warn(""),
|
(Level::Warn, None) => sess.struct_warn(""),
|
||||||
(Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
|
(Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
|
||||||
(Level::Deny | Level::Forbid, None) => sess.struct_err(""),
|
(Level::Deny | Level::Forbid, None) => sess.struct_err(""),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for future incompatibility lints and issue a stronger warning.
|
|
||||||
let lint_id = LintId::of(lint);
|
|
||||||
let future_incompatible = lint.future_incompatible;
|
|
||||||
|
|
||||||
// If this code originates in a foreign macro, aka something that this crate
|
// If this code originates in a foreign macro, aka something that this crate
|
||||||
// did not itself author, then it's likely that there's nothing this crate
|
// did not itself author, then it's likely that there's nothing this crate
|
||||||
// can do about it. We probably want to skip the lint entirely.
|
// can do about it. We probably want to skip the lint entirely.
|
||||||
|
@ -321,7 +332,7 @@ pub fn struct_lint_level<'s, 'd>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err.code(DiagnosticId::Lint(name));
|
err.code(DiagnosticId::Lint { name, has_future_breakage });
|
||||||
|
|
||||||
if let Some(future_incompatible) = future_incompatible {
|
if let Some(future_incompatible) = future_incompatible {
|
||||||
const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
|
const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
|
||||||
|
|
|
@ -18,3 +18,4 @@ rustc_span = { path = "../rustc_span" }
|
||||||
rustc_fs_util = { path = "../rustc_fs_util" }
|
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||||
num_cpus = "1.0"
|
num_cpus = "1.0"
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
|
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||||
|
|
|
@ -9,8 +9,8 @@ extern crate rustc_macros;
|
||||||
|
|
||||||
pub mod cgu_reuse_tracker;
|
pub mod cgu_reuse_tracker;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
#[macro_use]
|
pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass};
|
||||||
pub mod lint;
|
pub use rustc_lint_defs as lint;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
|
||||||
mod code_stats;
|
mod code_stats;
|
||||||
|
|
|
@ -893,6 +893,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||||
all `statement`s (including terminators), only `terminator` spans, or \
|
all `statement`s (including terminators), only `terminator` spans, or \
|
||||||
computed `block` spans (one span encompassing a block's terminator and \
|
computed `block` spans (one span encompassing a block's terminator and \
|
||||||
all statements)."),
|
all statements)."),
|
||||||
|
emit_future_incompat_report: bool = (false, parse_bool, [UNTRACKED],
|
||||||
|
"emits a future-incompatibility report for lints (RFC 2834)"),
|
||||||
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
|
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"emit a section containing stack size metadata (default: no)"),
|
"emit a section containing stack size metadata (default: no)"),
|
||||||
fewer_names: bool = (false, parse_bool, [TRACKED],
|
fewer_names: bool = (false, parse_bool, [TRACKED],
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::code_stats::CodeStats;
|
||||||
pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
|
pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
|
||||||
use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath};
|
use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath};
|
||||||
use crate::filesearch;
|
use crate::filesearch;
|
||||||
use crate::lint;
|
use crate::lint::{self, LintId};
|
||||||
use crate::parse::ParseSess;
|
use crate::parse::ParseSess;
|
||||||
use crate::search_paths::{PathKind, SearchPath};
|
use crate::search_paths::{PathKind, SearchPath};
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter;
|
||||||
use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
|
use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
|
||||||
use rustc_errors::json::JsonEmitter;
|
use rustc_errors::json::JsonEmitter;
|
||||||
use rustc_errors::registry::Registry;
|
use rustc_errors::registry::Registry;
|
||||||
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported};
|
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported};
|
||||||
|
use rustc_lint_defs::FutureBreakage;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
|
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
|
||||||
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
|
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
|
||||||
|
@ -40,6 +41,10 @@ use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub trait SessionLintStore: sync::Send + sync::Sync {
|
||||||
|
fn name_to_lint(&self, lint_name: &str) -> LintId;
|
||||||
|
}
|
||||||
|
|
||||||
pub struct OptimizationFuel {
|
pub struct OptimizationFuel {
|
||||||
/// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
|
/// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
|
||||||
remaining: u64,
|
remaining: u64,
|
||||||
|
@ -131,6 +136,8 @@ pub struct Session {
|
||||||
|
|
||||||
features: OnceCell<rustc_feature::Features>,
|
features: OnceCell<rustc_feature::Features>,
|
||||||
|
|
||||||
|
lint_store: OnceCell<Lrc<dyn SessionLintStore>>,
|
||||||
|
|
||||||
/// The maximum recursion limit for potentially infinitely recursive
|
/// The maximum recursion limit for potentially infinitely recursive
|
||||||
/// operations such as auto-dereference and monomorphization.
|
/// operations such as auto-dereference and monomorphization.
|
||||||
pub recursion_limit: OnceCell<Limit>,
|
pub recursion_limit: OnceCell<Limit>,
|
||||||
|
@ -297,6 +304,35 @@ impl Session {
|
||||||
pub fn finish_diagnostics(&self, registry: &Registry) {
|
pub fn finish_diagnostics(&self, registry: &Registry) {
|
||||||
self.check_miri_unleashed_features();
|
self.check_miri_unleashed_features();
|
||||||
self.diagnostic().print_error_count(registry);
|
self.diagnostic().print_error_count(registry);
|
||||||
|
self.emit_future_breakage();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_future_breakage(&self) {
|
||||||
|
if !self.opts.debugging_opts.emit_future_incompat_report {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let diags = self.diagnostic().take_future_breakage_diagnostics();
|
||||||
|
if diags.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If any future-breakage lints were registered, this lint store
|
||||||
|
// should be available
|
||||||
|
let lint_store = self.lint_store.get().expect("`lint_store` not initialized!");
|
||||||
|
let diags_and_breakage: Vec<(FutureBreakage, Diagnostic)> = diags
|
||||||
|
.into_iter()
|
||||||
|
.map(|diag| {
|
||||||
|
let lint_name = match &diag.code {
|
||||||
|
Some(DiagnosticId::Lint { name, has_future_breakage: true }) => name,
|
||||||
|
_ => panic!("Unexpected code in diagnostic {:?}", diag),
|
||||||
|
};
|
||||||
|
let lint = lint_store.name_to_lint(&lint_name);
|
||||||
|
let future_breakage =
|
||||||
|
lint.lint.future_incompatible.unwrap().future_breakage.unwrap();
|
||||||
|
(future_breakage, diag)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
self.parse_sess.span_diagnostic.emit_future_breakage_report(diags_and_breakage);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
|
pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
|
||||||
|
@ -337,6 +373,12 @@ impl Session {
|
||||||
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
|
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
|
||||||
self.diagnostic().struct_warn(msg)
|
self.diagnostic().struct_warn(msg)
|
||||||
}
|
}
|
||||||
|
pub fn struct_span_allow<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> {
|
||||||
|
self.diagnostic().struct_span_allow(sp, msg)
|
||||||
|
}
|
||||||
|
pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> {
|
||||||
|
self.diagnostic().struct_allow(msg)
|
||||||
|
}
|
||||||
pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> {
|
pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> {
|
||||||
self.diagnostic().struct_span_err(sp, msg)
|
self.diagnostic().struct_span_err(sp, msg)
|
||||||
}
|
}
|
||||||
|
@ -611,6 +653,13 @@ impl Session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_lint_store(&self, lint_store: Lrc<dyn SessionLintStore>) {
|
||||||
|
self.lint_store
|
||||||
|
.set(lint_store)
|
||||||
|
.map_err(|_| ())
|
||||||
|
.expect("`lint_store` was initialized twice");
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the flavor of LTO to use for this compilation.
|
/// Calculates the flavor of LTO to use for this compilation.
|
||||||
pub fn lto(&self) -> config::Lto {
|
pub fn lto(&self) -> config::Lto {
|
||||||
// If our target has codegen requirements ignore the command line
|
// If our target has codegen requirements ignore the command line
|
||||||
|
@ -1388,6 +1437,7 @@ pub fn build_session(
|
||||||
crate_types: OnceCell::new(),
|
crate_types: OnceCell::new(),
|
||||||
crate_disambiguator: OnceCell::new(),
|
crate_disambiguator: OnceCell::new(),
|
||||||
features: OnceCell::new(),
|
features: OnceCell::new(),
|
||||||
|
lint_store: OnceCell::new(),
|
||||||
recursion_limit: OnceCell::new(),
|
recursion_limit: OnceCell::new(),
|
||||||
type_length_limit: OnceCell::new(),
|
type_length_limit: OnceCell::new(),
|
||||||
const_eval_limit: OnceCell::new(),
|
const_eval_limit: OnceCell::new(),
|
||||||
|
|
|
@ -55,4 +55,7 @@ fn main() {
|
||||||
(&small as &[_]).into_iter();
|
(&small as &[_]).into_iter();
|
||||||
small[..].into_iter();
|
small[..].into_iter();
|
||||||
std::iter::IntoIterator::into_iter(&[1, 2]);
|
std::iter::IntoIterator::into_iter(&[1, 2]);
|
||||||
|
|
||||||
|
#[allow(array_into_iter)]
|
||||||
|
[0, 1].into_iter();
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,4 +55,7 @@ fn main() {
|
||||||
(&small as &[_]).into_iter();
|
(&small as &[_]).into_iter();
|
||||||
small[..].into_iter();
|
small[..].into_iter();
|
||||||
std::iter::IntoIterator::into_iter(&[1, 2]);
|
std::iter::IntoIterator::into_iter(&[1, 2]);
|
||||||
|
|
||||||
|
#[allow(array_into_iter)]
|
||||||
|
[0, 1].into_iter();
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,3 +109,139 @@ LL | Box::new(Box::new([0u8; 33])).into_iter();
|
||||||
|
|
||||||
warning: 12 warnings emitted
|
warning: 12 warnings emitted
|
||||||
|
|
||||||
|
Future incompatibility report: Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:9:11
|
||||||
|
|
|
||||||
|
LL | small.into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= note: `#[warn(array_into_iter)]` on by default
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:12:12
|
||||||
|
|
|
||||||
|
LL | [1, 2].into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:15:9
|
||||||
|
|
|
||||||
|
LL | big.into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:18:15
|
||||||
|
|
|
||||||
|
LL | [0u8; 33].into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:22:21
|
||||||
|
|
|
||||||
|
LL | Box::new(small).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:25:22
|
||||||
|
|
|
||||||
|
LL | Box::new([1, 2]).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:28:19
|
||||||
|
|
|
||||||
|
LL | Box::new(big).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:31:25
|
||||||
|
|
|
||||||
|
LL | Box::new([0u8; 33]).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:35:31
|
||||||
|
|
|
||||||
|
LL | Box::new(Box::new(small)).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:38:32
|
||||||
|
|
|
||||||
|
LL | Box::new(Box::new([1, 2])).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:41:29
|
||||||
|
|
|
||||||
|
LL | Box::new(Box::new(big)).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:44:35
|
||||||
|
|
|
||||||
|
LL | Box::new(Box::new([0u8; 33])).into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
Future breakage date: None, diagnostic:
|
||||||
|
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:60:12
|
||||||
|
|
|
||||||
|
LL | [0, 1].into_iter();
|
||||||
|
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/into-iter-on-arrays-lint.rs:59:13
|
||||||
|
|
|
||||||
|
LL | #[allow(array_into_iter)]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
|
||||||
pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
|
pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
|
||||||
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
|
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
|
||||||
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
|
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
|
||||||
pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"];
|
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
|
||||||
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
|
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
|
||||||
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
|
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
|
||||||
pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
|
pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
|
||||||
|
|
|
@ -36,6 +36,17 @@ struct DiagnosticSpan {
|
||||||
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
|
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct FutureIncompatReport {
|
||||||
|
future_incompat_report: Vec<FutureBreakageItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct FutureBreakageItem {
|
||||||
|
future_breakage_date: Option<String>,
|
||||||
|
diagnostic: Diagnostic,
|
||||||
|
}
|
||||||
|
|
||||||
impl DiagnosticSpan {
|
impl DiagnosticSpan {
|
||||||
/// Returns the deepest source span in the macro call stack with a given file name.
|
/// Returns the deepest source span in the macro call stack with a given file name.
|
||||||
/// This is either the supplied span, or the span for some macro callsite that expanded to it.
|
/// This is either the supplied span, or the span for some macro callsite that expanded to it.
|
||||||
|
@ -68,6 +79,13 @@ struct DiagnosticCode {
|
||||||
explanation: Option<String>,
|
explanation: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rustfix_diagnostics_only(output: &str) -> String {
|
||||||
|
output
|
||||||
|
.lines()
|
||||||
|
.filter(|line| line.starts_with('{') && serde_json::from_str::<Diagnostic>(line).is_ok())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn extract_rendered(output: &str) -> String {
|
pub fn extract_rendered(output: &str) -> String {
|
||||||
output
|
output
|
||||||
.lines()
|
.lines()
|
||||||
|
@ -75,6 +93,28 @@ pub fn extract_rendered(output: &str) -> String {
|
||||||
if line.starts_with('{') {
|
if line.starts_with('{') {
|
||||||
if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
|
if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
|
||||||
diagnostic.rendered
|
diagnostic.rendered
|
||||||
|
} else if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(line) {
|
||||||
|
if report.future_incompat_report.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(format!(
|
||||||
|
"Future incompatibility report: {}",
|
||||||
|
report
|
||||||
|
.future_incompat_report
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| {
|
||||||
|
format!(
|
||||||
|
"Future breakage date: {}, diagnostic:\n{}",
|
||||||
|
item.future_breakage_date
|
||||||
|
.unwrap_or_else(|| "None".to_string()),
|
||||||
|
item.diagnostic
|
||||||
|
.rendered
|
||||||
|
.unwrap_or_else(|| "Not rendered".to_string())
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<String>()
|
||||||
|
))
|
||||||
|
}
|
||||||
} else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
|
} else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
|
||||||
// Ignore the notification.
|
// Ignore the notification.
|
||||||
None
|
None
|
||||||
|
@ -108,6 +148,11 @@ fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) ->
|
||||||
expected_errors
|
expected_errors
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
// Ignore the future compat report message - this is handled
|
||||||
|
// by `extract_rendered`
|
||||||
|
if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
proc_res.fatal(Some(&format!(
|
proc_res.fatal(Some(&format!(
|
||||||
"failed to decode compiler output as json: \
|
"failed to decode compiler output as json: \
|
||||||
`{}`\nline: {}\noutput: {}",
|
`{}`\nline: {}\noutput: {}",
|
||||||
|
@ -115,6 +160,7 @@ fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) ->
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1942,6 +1942,7 @@ impl<'test> TestCx<'test> {
|
||||||
}
|
}
|
||||||
rustc.arg("-Zui-testing");
|
rustc.arg("-Zui-testing");
|
||||||
rustc.arg("-Zdeduplicate-diagnostics=no");
|
rustc.arg("-Zdeduplicate-diagnostics=no");
|
||||||
|
rustc.arg("-Zemit-future-incompat-report");
|
||||||
}
|
}
|
||||||
MirOpt => {
|
MirOpt => {
|
||||||
rustc.args(&[
|
rustc.args(&[
|
||||||
|
@ -2978,6 +2979,7 @@ impl<'test> TestCx<'test> {
|
||||||
self.prune_duplicate_outputs(&modes_to_prune);
|
self.prune_duplicate_outputs(&modes_to_prune);
|
||||||
|
|
||||||
let mut errors = self.load_compare_outputs(&proc_res, TestOutput::Compile, explicit);
|
let mut errors = self.load_compare_outputs(&proc_res, TestOutput::Compile, explicit);
|
||||||
|
let rustfix_input = json::rustfix_diagnostics_only(&proc_res.stderr);
|
||||||
|
|
||||||
if self.config.compare_mode.is_some() {
|
if self.config.compare_mode.is_some() {
|
||||||
// don't test rustfix with nll right now
|
// don't test rustfix with nll right now
|
||||||
|
@ -2988,7 +2990,7 @@ impl<'test> TestCx<'test> {
|
||||||
// This will return an empty `Vec` in case the executed test file has a
|
// This will return an empty `Vec` in case the executed test file has a
|
||||||
// `compile-flags: --error-format=xxxx` header with a value other than `json`.
|
// `compile-flags: --error-format=xxxx` header with a value other than `json`.
|
||||||
let suggestions = get_suggestions_from_json(
|
let suggestions = get_suggestions_from_json(
|
||||||
&proc_res.stderr,
|
&rustfix_input,
|
||||||
&HashSet::new(),
|
&HashSet::new(),
|
||||||
Filter::MachineApplicableOnly,
|
Filter::MachineApplicableOnly,
|
||||||
)
|
)
|
||||||
|
@ -3015,7 +3017,7 @@ impl<'test> TestCx<'test> {
|
||||||
// Apply suggestions from rustc to the code itself
|
// Apply suggestions from rustc to the code itself
|
||||||
let unfixed_code = self.load_expected_output_from_path(&self.testpaths.file).unwrap();
|
let unfixed_code = self.load_expected_output_from_path(&self.testpaths.file).unwrap();
|
||||||
let suggestions = get_suggestions_from_json(
|
let suggestions = get_suggestions_from_json(
|
||||||
&proc_res.stderr,
|
&rustfix_input,
|
||||||
&HashSet::new(),
|
&HashSet::new(),
|
||||||
if self.props.rustfix_only_machine_applicable {
|
if self.props.rustfix_only_machine_applicable {
|
||||||
Filter::MachineApplicableOnly
|
Filter::MachineApplicableOnly
|
||||||
|
@ -3121,10 +3123,12 @@ impl<'test> TestCx<'test> {
|
||||||
self.fatal_proc_rec("failed to compile fixed code", &res);
|
self.fatal_proc_rec("failed to compile fixed code", &res);
|
||||||
}
|
}
|
||||||
if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable {
|
if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable {
|
||||||
|
if !json::rustfix_diagnostics_only(&res.stderr).is_empty() {
|
||||||
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
|
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_mir_opt_test(&self) {
|
fn run_mir_opt_test(&self) {
|
||||||
let pm = self.pass_mode();
|
let pm = self.pass_mode();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue