Implement rustc side of report-future-incompat

This commit is contained in:
Aaron Hill 2020-08-13 15:41:52 -04:00
parent ffe52882ed
commit 23018a55d9
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
22 changed files with 332 additions and 114 deletions

View File

@ -3638,6 +3638,7 @@ dependencies = [
"annotate-snippets 0.8.0",
"atty",
"rustc_data_structures",
"rustc_lint_defs",
"rustc_macros",
"rustc_serialize",
"rustc_span",
@ -3830,6 +3831,18 @@ dependencies = [
"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]]
name = "rustc_llvm"
version = "0.0.0"
@ -4112,6 +4125,7 @@ dependencies = [
"rustc_errors",
"rustc_feature",
"rustc_fs_util",
"rustc_lint_defs",
"rustc_macros",
"rustc_serialize",
"rustc_span",

View File

@ -308,8 +308,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
E0726,
"implicit elided lifetime not allowed here"
);
rustc_session::lint::add_elided_lifetime_in_path_suggestion(
&self.sess,
rustc_errors::add_elided_lifetime_in_path_suggestion(
&self.sess.source_map(),
&mut err,
expected_lifetimes,
path_span,

View File

@ -13,6 +13,7 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_macros = { path = "../rustc_macros" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
unicode-width = "0.1.4"
atty = "0.2"
termcolor = "1.0"

View File

@ -72,6 +72,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType {
Level::Help => AnnotationType::Help,
// FIXME(#59346): Not sure how to map these two levels
Level::Cancelled | Level::FailureNote => AnnotationType::Error,
Level::Allow => panic!("Should not call with Allow"),
}
}
@ -143,7 +144,8 @@ impl AnnotateSnippetEmitterWriter {
title: Some(Annotation {
label: Some(&message),
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),
}),

View File

@ -1,10 +1,10 @@
use crate::snippet::Style;
use crate::Applicability;
use crate::CodeSuggestion;
use crate::Level;
use crate::Substitution;
use crate::SubstitutionPart;
use crate::SuggestionStyle;
use rustc_lint_defs::Applicability;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use std::fmt;
@ -27,7 +27,7 @@ pub struct Diagnostic {
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DiagnosticId {
Error(String),
Lint(String),
Lint { name: String, has_future_breakage: bool },
}
/// For example a note attached to an error.
@ -107,7 +107,14 @@ impl Diagnostic {
match self.level {
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,
}
}

View File

@ -1,5 +1,6 @@
use crate::{Applicability, Handler, Level, StashKey};
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString};
use crate::{Handler, Level, StashKey};
use rustc_lint_defs::Applicability;
use rustc_span::{MultiSpan, Span};
use std::fmt::{self, Debug};

View File

@ -9,14 +9,15 @@
use Destination::*;
use rustc_lint_defs::FutureBreakage;
use rustc_span::source_map::SourceMap;
use rustc_span::{MultiSpan, SourceFile, Span};
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
use crate::{
pluralize, CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle,
};
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle};
use rustc_lint_defs::pluralize;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
@ -192,6 +193,8 @@ pub trait Emitter {
/// other formats can, and will, simply ignore it.
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"
fn should_show_explain(&self) -> bool {
true

View File

@ -13,8 +13,9 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
use crate::{Applicability, DiagnosticId};
use crate::DiagnosticId;
use crate::{CodeSuggestion, SubDiagnostic};
use rustc_lint_defs::{Applicability, FutureBreakage};
use rustc_data_structures::sync::Lrc;
use rustc_span::hygiene::ExpnData;
@ -131,6 +132,30 @@ 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 result = if self.pretty {
writeln!(&mut self.dst, "{}", as_pretty_json(&data))
} else {
writeln!(&mut self.dst, "{}", as_json(&data))
}
.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>> {
Some(&self.sm)
}
@ -223,6 +248,12 @@ struct ArtifactNotification<'a> {
emit: &'a str,
}
#[derive(Encodable)]
struct FutureBreakageItem {
future_breakage_date: Option<&'static str>,
diagnostic: Diagnostic,
}
impl Diagnostic {
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
let sugg = diag.suggestions.iter().map(|sugg| Diagnostic {
@ -432,7 +463,7 @@ impl DiagnosticCode {
s.map(|s| {
let s = match s {
DiagnosticId::Error(s) => s,
DiagnosticId::Lint(s) => s,
DiagnosticId::Lint { name, has_future_breakage: _ } => name,
};
let je_result =
je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap();

View File

@ -21,6 +21,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{self, Lock, Lrc};
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::{Loc, MultiSpan, Span};
@ -49,30 +51,6 @@ pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
#[cfg(target_arch = "x86_64")]
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)]
pub enum SuggestionStyle {
/// Hide the suggested code when displaying this suggestion inline.
@ -321,6 +299,8 @@ struct HandlerInner {
/// The warning count, used for a recap upon finishing
deduplicated_warn_count: usize,
future_breakage_diagnostics: Vec<Diagnostic>,
}
/// A key denoting where from a diagnostic was stashed.
@ -434,6 +414,7 @@ impl Handler {
emitted_diagnostic_codes: Default::default(),
emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(),
}),
}
}
@ -503,6 +484,17 @@ impl Handler {
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`.
/// Also include a code.
pub fn struct_span_warn_with_code(
@ -525,6 +517,11 @@ impl Handler {
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`.
pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
let mut result = self.struct_err(msg);
@ -693,6 +690,10 @@ impl Handler {
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) {
self.inner.borrow_mut().abort_if_errors()
}
@ -723,6 +724,10 @@ impl Handler {
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) {
self.inner.borrow_mut().delay_as_bug(diagnostic)
}
@ -748,12 +753,23 @@ impl HandlerInner {
return;
}
if diagnostic.has_future_breakage() {
self.future_breakage_diagnostics.push(diagnostic.clone());
}
if diagnostic.level == Warning && !self.flags.can_emit_warnings {
if diagnostic.has_future_breakage() {
(*TRACK_DIAGNOSTICS)(diagnostic);
}
return;
}
(*TRACK_DIAGNOSTICS)(diagnostic);
if diagnostic.level == Allow {
return;
}
if let Some(ref code) = diagnostic.code {
self.emitted_diagnostic_codes.insert(code.clone());
}
@ -992,6 +1008,7 @@ pub enum Level {
Help,
Cancelled,
FailureNote,
Allow,
}
impl fmt::Display for Level {
@ -1017,7 +1034,7 @@ impl Level {
spec.set_fg(Some(Color::Cyan)).set_intense(true);
}
FailureNote => {}
Cancelled => unreachable!(),
Allow | Cancelled => unreachable!(),
}
spec
}
@ -1031,6 +1048,7 @@ impl Level {
Help => "help",
FailureNote => "failure-note",
Cancelled => panic!("Shouldn't call on cancelled error"),
Allow => panic!("Shouldn't call on allowed error"),
}
}
@ -1039,11 +1057,46 @@ impl Level {
}
}
#[macro_export]
macro_rules! pluralize {
($x:expr) => {
if $x != 1 { "s" } else { "" }
pub fn add_elided_lifetime_in_path_suggestion(
source_map: &SourceMap,
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) = 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

View File

@ -275,7 +275,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) {

View File

@ -477,6 +477,7 @@ fn test_debugging_options_tracking_hash() {
untracked!(dump_mir_dir, String::from("abc"));
untracked!(dump_mir_exclude_pass_number, true);
untracked!(dump_mir_graphviz, true);
untracked!(emit_future_compat_report, true);
untracked!(emit_stack_sizes, true);
untracked!(hir_stats, true);
untracked!(identify_regions, true);

View File

@ -3,7 +3,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::lint::FutureIncompatibleInfo;
use rustc_session::lint::FutureBreakage;
use rustc_span::symbol::sym;
declare_lint! {
@ -38,6 +38,9 @@ declare_lint! {
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>",
edition: None,
future_breakage: Some(FutureBreakage {
date: None
})
};
}

View File

@ -44,7 +44,6 @@ use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
use rustc_session::lint::FutureIncompatibleInfo;
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;

View File

@ -22,7 +22,7 @@ use rustc_ast as ast;
use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::FxHashMap;
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::def::Res;
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::print::with_no_trimmed_paths;
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::Session;
use rustc_session::SessionLintStore;
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
use rustc_target::abi::LayoutOf;
@ -69,6 +70,20 @@ pub struct LintStore {
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.
enum TargetLint {
/// A direct lint target
@ -543,7 +558,7 @@ pub trait LintContext: Sized {
anon_lts,
) => {
add_elided_lifetime_in_path_suggestion(
sess,
sess.source_map(),
&mut db,
n,
path_span,

View 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" }

View File

@ -4,7 +4,6 @@
//! compiler code, rather than using their own custom pass. Those
//! lints are all available in `rustc_lint::builtin`.
use crate::lint::FutureIncompatibleInfo;
use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
use rustc_span::edition::Edition;
use rustc_span::symbol::sym;

View File

@ -1,12 +1,45 @@
#[macro_use]
extern crate rustc_macros;
pub use self::Level::*;
use rustc_ast::node_id::{NodeId, NodeMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
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.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Level {
@ -106,6 +139,21 @@ pub struct FutureIncompatibleInfo {
/// If this is an edition fixing lint, the edition in which
/// this lint becomes obsolete
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 {
@ -331,31 +379,34 @@ macro_rules! declare_lint {
);
);
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
$(@future_incompatible = $fi:expr;)?
$(@feature_gate = $gate:expr;)?
$(@future_incompatible = FutureIncompatibleInfo { $($field:ident : $val:expr),* $(,)* }; )?
$($v:ident),*) => (
$(#[$attr])*
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
$vis static $NAME: &$crate::Lint = &$crate::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
default_level: $crate::$Level,
desc: $desc,
edition_lint_opts: None,
is_plugin: false,
$($v: true,)*
$(future_incompatible: Some($fi),)*
$(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,
$lint_edition: expr => $edition_level: ident
) => (
$(#[$attr])*
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
$vis static $NAME: &$crate::Lint = &$crate::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
default_level: $crate::$Level,
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,
is_plugin: false,
};
@ -380,9 +431,9 @@ macro_rules! declare_tool_lint {
$external:expr
) => (
$(#[$attr])*
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
$vis static $NAME: &$crate::Lint = &$crate::Lint {
name: &concat!(stringify!($tool), "::", stringify!($NAME)),
default_level: $crate::lint::$Level,
default_level: $crate::$Level,
desc: $desc,
edition_lint_opts: None,
report_in_external_macro: $external,
@ -413,11 +464,11 @@ pub trait LintPass {
#[macro_export]
macro_rules! impl_lint_pass {
($ty:ty => [$($lint:expr),* $(,)?]) => {
impl $crate::lint::LintPass for $ty {
impl $crate::LintPass for $ty {
fn name(&self) -> &'static str { stringify!($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),*]);
};
}
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,
);
}

View File

@ -225,20 +225,31 @@ pub fn struct_lint_level<'s, 'd>(
span: Option<MultiSpan>,
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) {
(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;
}
}
(Level::Warn, Some(span)) => sess.struct_span_warn(span, ""),
(Level::Warn, None) => sess.struct_warn(""),
(Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
(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
// 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.
@ -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 {
const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \

View File

@ -18,3 +18,4 @@ rustc_span = { path = "../rustc_span" }
rustc_fs_util = { path = "../rustc_fs_util" }
num_cpus = "1.0"
rustc_ast = { path = "../rustc_ast" }
rustc_lint_defs = { path = "../rustc_lint_defs" }

View File

@ -9,8 +9,8 @@ extern crate rustc_macros;
pub mod cgu_reuse_tracker;
pub mod utils;
#[macro_use]
pub mod lint;
pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass};
pub use rustc_lint_defs as lint;
pub mod parse;
mod code_stats;

View File

@ -893,6 +893,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
all `statement`s (including terminators), only `terminator` spans, or \
computed `block` spans (one span encompassing a block's terminator and \
all statements)."),
emit_future_compat_report: bool = (false, parse_bool, [UNTRACKED],
"emits a future-compatibility report for lints (RFC 2834)"),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emit a section containing stack size metadata (default: no)"),
fewer_names: bool = (false, parse_bool, [TRACKED],

View File

@ -3,7 +3,7 @@ use crate::code_stats::CodeStats;
pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath};
use crate::filesearch;
use crate::lint;
use crate::lint::{self, LintId};
use crate::parse::ParseSess;
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::json::JsonEmitter;
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::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
@ -40,6 +41,10 @@ use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
pub trait SessionLintStore: sync::Send + sync::Sync {
fn name_to_lint(&self, lint_name: &str) -> LintId;
}
pub struct OptimizationFuel {
/// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
remaining: u64,
@ -131,6 +136,8 @@ pub struct Session {
features: OnceCell<rustc_feature::Features>,
lint_store: OnceCell<Lrc<dyn SessionLintStore>>,
/// The maximum recursion limit for potentially infinitely recursive
/// operations such as auto-dereference and monomorphization.
pub recursion_limit: OnceCell<Limit>,
@ -297,6 +304,35 @@ impl Session {
pub fn finish_diagnostics(&self, registry: &Registry) {
self.check_miri_unleashed_features();
self.diagnostic().print_error_count(registry);
self.emit_future_breakage();
}
fn emit_future_breakage(&self) {
if !self.opts.debugging_opts.emit_future_compat_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 {
@ -337,6 +373,12 @@ impl Session {
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
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<'_> {
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.
pub fn lto(&self) -> config::Lto {
// If our target has codegen requirements ignore the command line
@ -1388,6 +1437,7 @@ pub fn build_session(
crate_types: OnceCell::new(),
crate_disambiguator: OnceCell::new(),
features: OnceCell::new(),
lint_store: OnceCell::new(),
recursion_limit: OnceCell::new(),
type_length_limit: OnceCell::new(),
const_eval_limit: OnceCell::new(),