Convert to inline diagnostics in rustc_lint
This commit is contained in:
parent
c7f5f3e0d5
commit
c814f76c06
17 changed files with 1307 additions and 1813 deletions
|
|
@ -4143,7 +4143,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
|
|||
|
|
@ -111,11 +111,7 @@ pub fn default_translator() -> Translator {
|
|||
Translator::with_fallback_bundle(DEFAULT_LOCALE_RESOURCES.to_vec(), false)
|
||||
}
|
||||
|
||||
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
|
||||
// tidy-alphabetical-start
|
||||
rustc_lint::DEFAULT_LOCALE_RESOURCE,
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[];
|
||||
|
||||
/// Exit status code used for successful compilation and help output.
|
||||
pub const EXIT_SUCCESS: i32 = 0;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
|||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -108,16 +108,18 @@ impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_closure_returning_async_block)]
|
||||
#[diag("closure returning async block can be made into an async closure")]
|
||||
struct ClosureReturningAsyncBlock {
|
||||
#[label]
|
||||
#[label(
|
||||
"this async block can be removed, and the closure can be turned into an async closure"
|
||||
)]
|
||||
async_decl_span: Span,
|
||||
#[subdiagnostic]
|
||||
sugg: AsyncClosureSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
|
||||
#[multipart_suggestion("turn this into an async closure", applicability = "maybe-incorrect")]
|
||||
struct AsyncClosureSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
deletion_span: Span,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind};
|
|||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_errors::{Applicability, LintDiagnostic};
|
||||
use rustc_errors::{Applicability, LintDiagnostic, inline_fluent};
|
||||
use rustc_feature::GateIssue;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::{AttributeKind, DocAttribute};
|
||||
|
|
@ -61,10 +61,7 @@ use crate::lints::{
|
|||
BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
|
||||
BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
|
||||
};
|
||||
use crate::{
|
||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
|
||||
fluent_generated as fluent,
|
||||
};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
|
||||
declare_lint! {
|
||||
/// The `while_true` lint detects `while true { }`.
|
||||
///
|
||||
|
|
@ -2655,8 +2652,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
|||
let conjured_ty = cx.typeck_results().expr_ty(expr);
|
||||
if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
|
||||
let msg = match init {
|
||||
InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
|
||||
InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit,
|
||||
InitKind::Zeroed => {
|
||||
inline_fluent!("the type `{$ty}` does not permit zero-initialization")
|
||||
}
|
||||
InitKind::Uninit => {
|
||||
inline_fluent!("the type `{$ty}` does not permit being left uninitialized")
|
||||
}
|
||||
};
|
||||
let sub = BuiltinUnpermittedTypeInitSub { err };
|
||||
cx.emit_span_lint(
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
|
||||
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic, inline_fluent};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_overruled_attribute, code = E0453)]
|
||||
#[diag("{$lint_level}({$lint_source}) incompatible with previous forbid", code = E0453)]
|
||||
pub(crate) struct OverruledAttribute<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
#[label("overruled by previous forbid")]
|
||||
pub overruled: Span,
|
||||
pub lint_level: &'a str,
|
||||
pub lint_source: Symbol,
|
||||
|
|
@ -29,24 +27,24 @@ impl Subdiagnostic for OverruledAttributeSub {
|
|||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
match self {
|
||||
OverruledAttributeSub::DefaultSource { id } => {
|
||||
diag.note(fluent::lint_default_source);
|
||||
diag.note(inline_fluent!("`forbid` lint level is the default for {$id}"));
|
||||
diag.arg("id", id);
|
||||
}
|
||||
OverruledAttributeSub::NodeSource { span, reason } => {
|
||||
diag.span_label(span, fluent::lint_node_source);
|
||||
diag.span_label(span, inline_fluent!("`forbid` level set here"));
|
||||
if let Some(rationale) = reason {
|
||||
diag.note(rationale.to_string());
|
||||
}
|
||||
}
|
||||
OverruledAttributeSub::CommandLineSource => {
|
||||
diag.note(fluent::lint_command_line_source);
|
||||
diag.note(inline_fluent!("`forbid` lint level was set on command line"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_malformed_attribute, code = E0452)]
|
||||
#[diag("malformed lint attribute input", code = E0452)]
|
||||
pub(crate) struct MalformedAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -56,50 +54,55 @@ pub(crate) struct MalformedAttribute {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum MalformedAttributeSub {
|
||||
#[label(lint_bad_attribute_argument)]
|
||||
#[label("bad attribute argument")]
|
||||
BadAttributeArgument(#[primary_span] Span),
|
||||
#[label(lint_reason_must_be_string_literal)]
|
||||
#[label("reason must be a string literal")]
|
||||
ReasonMustBeStringLiteral(#[primary_span] Span),
|
||||
#[label(lint_reason_must_come_last)]
|
||||
#[label("reason in lint attribute must come last")]
|
||||
ReasonMustComeLast(#[primary_span] Span),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_unknown_tool_in_scoped_lint, code = E0710)]
|
||||
#[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`", code = E0710)]
|
||||
pub(crate) struct UnknownToolInScopedLint {
|
||||
#[primary_span]
|
||||
pub span: Option<Span>,
|
||||
pub tool_name: Symbol,
|
||||
pub lint_name: String,
|
||||
#[help]
|
||||
#[help("add `#![register_tool({$tool_name})]` to the crate root")]
|
||||
pub is_nightly_build: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = E0783)]
|
||||
#[diag("`...` range patterns are deprecated", code = E0783)]
|
||||
pub(crate) struct BuiltinEllipsisInclusiveRangePatterns {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
|
||||
#[suggestion(
|
||||
"use `..=` for an inclusive range",
|
||||
style = "short",
|
||||
code = "{replace}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
pub replace: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_requested_level)]
|
||||
#[note("requested on the command line with `{$level} {$lint_name}`")]
|
||||
pub(crate) struct RequestedLevel<'a> {
|
||||
pub level: Level,
|
||||
pub lint_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_unsupported_group, code = E0602)]
|
||||
#[diag("`{$lint_group}` lint group is not supported with ´--force-warn´", code = E0602)]
|
||||
pub(crate) struct UnsupportedGroup {
|
||||
pub lint_group: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_check_name_unknown_tool, code = E0602)]
|
||||
#[diag("unknown lint tool: `{$tool_name}`", code = E0602)]
|
||||
pub(crate) struct CheckNameUnknownTool<'a> {
|
||||
pub tool_name: Symbol,
|
||||
#[subdiagnostic]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ use std::ops::ControlFlow;
|
|||
|
||||
use hir::intravisit::{self, Visitor};
|
||||
use rustc_ast::Recovered;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle};
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle, inline_fluent,
|
||||
};
|
||||
use rustc_hir::{self as hir, HirIdSet};
|
||||
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
|
|
@ -303,13 +305,15 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_if_let_rescope)]
|
||||
#[diag("`if let` assigns a shorter lifetime since Edition 2024")]
|
||||
struct IfLetRescopeLint {
|
||||
#[subdiagnostic]
|
||||
destructors: Vec<DestructorLabel>,
|
||||
#[label]
|
||||
#[label(
|
||||
"this value has a significant drop implementation which may observe a major change in drop order and requires your discretion"
|
||||
)]
|
||||
significant_droppers: Vec<Span>,
|
||||
#[help]
|
||||
#[help("the value is now dropped here in Edition 2024")]
|
||||
lifetime_ends: Vec<Span>,
|
||||
#[subdiagnostic]
|
||||
rewrite: Option<IfLetRescopeRewrite>,
|
||||
|
|
@ -352,7 +356,9 @@ impl Subdiagnostic for IfLetRescopeRewrite {
|
|||
.chain(repeat_n('}', closing_brackets.count))
|
||||
.collect(),
|
||||
));
|
||||
let msg = diag.eagerly_translate(crate::fluent_generated::lint_suggestion);
|
||||
let msg = diag.eagerly_translate(inline_fluent!(
|
||||
"a `match` with a single arm can preserve the drop order up to Edition 2021"
|
||||
));
|
||||
diag.multipart_suggestion_with_style(
|
||||
msg,
|
||||
suggestions,
|
||||
|
|
@ -363,7 +369,12 @@ impl Subdiagnostic for IfLetRescopeRewrite {
|
|||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_if_let_dtor)]
|
||||
#[note(
|
||||
"{$dtor_kind ->
|
||||
[dyn] value may invoke a custom destructor because it contains a trait object
|
||||
*[concrete] value invokes this custom destructor
|
||||
}"
|
||||
)]
|
||||
struct DestructorLabel {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::cell::LazyCell;
|
|||
use rustc_data_structures::debug_assert_matches;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{LintDiagnostic, Subdiagnostic};
|
||||
use rustc_errors::{LintDiagnostic, Subdiagnostic, inline_fluent};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
|
@ -28,7 +28,7 @@ use rustc_trait_selection::errors::{
|
|||
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
||||
use crate::{LateContext, LateLintPass, fluent_generated as fluent};
|
||||
use crate::{LateContext, LateLintPass};
|
||||
|
||||
declare_lint! {
|
||||
/// The `impl_trait_overcaptures` lint warns against cases where lifetime
|
||||
|
|
@ -435,11 +435,23 @@ struct ImplTraitOvercapturesLint<'tcx> {
|
|||
|
||||
impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
|
||||
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
|
||||
diag.primary_message(fluent::lint_impl_trait_overcaptures);
|
||||
diag.primary_message(inline_fluent!(
|
||||
"`{$self_ty}` will capture more lifetimes than possibly intended in edition 2024"
|
||||
));
|
||||
diag.arg("self_ty", self.self_ty.to_string())
|
||||
.arg("num_captured", self.num_captured)
|
||||
.span_note(self.uncaptured_spans, fluent::lint_note)
|
||||
.note(fluent::lint_note2);
|
||||
.span_note(
|
||||
self.uncaptured_spans,
|
||||
inline_fluent!(
|
||||
"specifically, {$num_captured ->
|
||||
[one] this lifetime is
|
||||
*[other] these lifetimes are
|
||||
} in scope but not mentioned in the type's bounds"
|
||||
),
|
||||
)
|
||||
.note(inline_fluent!(
|
||||
"all lifetimes in scope will be captured by `impl Trait`s in edition 2024"
|
||||
));
|
||||
if let Some(suggestion) = self.suggestion {
|
||||
suggestion.add_to_diag(diag);
|
||||
}
|
||||
|
|
@ -447,9 +459,9 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_impl_trait_redundant_captures)]
|
||||
#[diag("all possible in-scope parameters are already captured, so `use<...>` syntax is redundant")]
|
||||
struct ImplTraitRedundantCapturesLint {
|
||||
#[suggestion(lint_suggestion, code = "", applicability = "machine-applicable")]
|
||||
#[suggestion("remove the `use<...>` syntax", code = "", applicability = "machine-applicable")]
|
||||
capturing_span: Span,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_ast::attr::AttributeExt;
|
|||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
|
||||
use rustc_errors::{Diag, LintDiagnostic, MultiSpan, inline_fluent};
|
||||
use rustc_feature::{Features, GateIssue};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
|
|
@ -31,7 +31,6 @@ use crate::errors::{
|
|||
CheckNameUnknownTool, MalformedAttribute, MalformedAttributeSub, OverruledAttribute,
|
||||
OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::late::unerased_lint_store;
|
||||
use crate::lints::{
|
||||
DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
|
||||
|
|
@ -942,9 +941,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
let lint = builtin::UNKNOWN_LINTS;
|
||||
let level = self.lint_level(builtin::UNKNOWN_LINTS);
|
||||
lint_level(self.sess, lint, level, Some(span.into()), |lint| {
|
||||
lint.primary_message(fluent::lint_unknown_gated_lint);
|
||||
lint.primary_message(inline_fluent!("unknown lint: `{$name}`"));
|
||||
lint.arg("name", lint_id.lint.name_lower());
|
||||
lint.note(fluent::lint_note);
|
||||
lint.note(inline_fluent!("the `{$name}` lint is unstable"));
|
||||
rustc_session::parse::add_feature_diagnostics_for_issue(
|
||||
lint,
|
||||
&self.sess,
|
||||
|
|
|
|||
|
|
@ -139,8 +139,6 @@ pub use rustc_errors::BufferedEarlyLint;
|
|||
pub use rustc_session::lint::Level::{self, *};
|
||||
pub use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec};
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
levels::provide(providers);
|
||||
expect::provide(providers);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::{Applicability, inline_fluent};
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::{bug, ty};
|
||||
|
|
@ -10,7 +10,7 @@ use rustc_span::{InnerSpan, Span, Symbol, hygiene, sym};
|
|||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
|
||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
declare_lint! {
|
||||
/// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first
|
||||
|
|
@ -121,20 +121,20 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
}
|
||||
|
||||
cx.span_lint(NON_FMT_PANICS, arg_span, |lint| {
|
||||
lint.primary_message(fluent::lint_non_fmt_panic);
|
||||
lint.primary_message(inline_fluent!("panic message is not a string literal"));
|
||||
lint.arg("name", symbol);
|
||||
lint.note(fluent::lint_note);
|
||||
lint.note(fluent::lint_more_info_note);
|
||||
lint.note(inline_fluent!("this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021"));
|
||||
lint.note(inline_fluent!("for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>"));
|
||||
if !is_arg_inside_call(arg_span, span) {
|
||||
// No clue where this argument is coming from.
|
||||
return;
|
||||
}
|
||||
if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
|
||||
// A case of `panic!(format!(..))`.
|
||||
lint.note(fluent::lint_supports_fmt_note);
|
||||
lint.note(inline_fluent!("the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here"));
|
||||
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
|
||||
lint.multipart_suggestion(
|
||||
fluent::lint_supports_fmt_suggestion,
|
||||
inline_fluent!("remove the `format!(..)` macro call"),
|
||||
vec![
|
||||
(arg_span.until(open.shrink_to_hi()), "".into()),
|
||||
(close.until(arg_span.shrink_to_hi()), "".into()),
|
||||
|
|
@ -178,7 +178,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
if suggest_display {
|
||||
lint.span_suggestion_verbose(
|
||||
arg_span.shrink_to_lo(),
|
||||
fluent::lint_display_suggestion,
|
||||
inline_fluent!(r#"add a "{"{"}{"}"}" format string to `Display` the message"#),
|
||||
"\"{}\", ",
|
||||
fmt_applicability,
|
||||
);
|
||||
|
|
@ -186,7 +186,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
lint.arg("ty", ty);
|
||||
lint.span_suggestion_verbose(
|
||||
arg_span.shrink_to_lo(),
|
||||
fluent::lint_debug_suggestion,
|
||||
inline_fluent!(r#"add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}`"#),
|
||||
"\"{:?}\", ",
|
||||
fmt_applicability,
|
||||
);
|
||||
|
|
@ -196,7 +196,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
if let Some((open, close, del)) = find_delimiters(cx, span) {
|
||||
lint.arg("already_suggested", suggest_display || suggest_debug);
|
||||
lint.multipart_suggestion(
|
||||
fluent::lint_panic_suggestion,
|
||||
inline_fluent!("{$already_suggested ->
|
||||
[true] or use
|
||||
*[false] use
|
||||
} std::panic::panic_any instead"),
|
||||
if del == '(' {
|
||||
vec![(span.until(open), "std::panic::panic_any".into())]
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::{MultiSpan, inline_fluent};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
|
||||
|
|
@ -9,7 +9,7 @@ use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
|||
use rustc_span::{ExpnKind, Span, kw};
|
||||
|
||||
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
|
||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
declare_lint! {
|
||||
/// The `non_local_definitions` lint checks for `impl` blocks and `#[macro_export]`
|
||||
|
|
@ -210,7 +210,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
if !doctest {
|
||||
ms.push_span_label(
|
||||
cx.tcx.def_span(parent),
|
||||
fluent::lint_non_local_definitions_impl_move_help,
|
||||
inline_fluent!(
|
||||
"move the `impl` block outside of this {$body_kind_descr} {$depth ->
|
||||
[one] `{$body_name}`
|
||||
*[other] `{$body_name}` and up {$depth} bodies
|
||||
}"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,11 +202,11 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_opaque_hidden_inferred_bound)]
|
||||
#[diag("opaque type `{$ty}` does not satisfy its associated type bounds")]
|
||||
struct OpaqueHiddenInferredBoundLint<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
proj_ty: Ty<'tcx>,
|
||||
#[label(lint_specifically)]
|
||||
#[label("this associated type bound is unsatisfied for `{$proj_ty}`")]
|
||||
assoc_pred_span: Span,
|
||||
#[subdiagnostic]
|
||||
add_bound: Option<AddBound<'tcx>>,
|
||||
|
|
@ -214,7 +214,7 @@ struct OpaqueHiddenInferredBoundLint<'tcx> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
lint_opaque_hidden_inferred_bound_sugg,
|
||||
"add this bound",
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable",
|
||||
code = " + {trait_ref}"
|
||||
|
|
|
|||
|
|
@ -369,8 +369,10 @@ fn check_unnecessary_transmute<'tcx>(
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_undefined_transmute)]
|
||||
#[note]
|
||||
#[note(lint_note2)]
|
||||
#[help]
|
||||
#[diag("pointers cannot be transmuted to integers during const eval")]
|
||||
#[note("at compile-time, pointers do not have an integer value")]
|
||||
#[note(
|
||||
"avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior"
|
||||
)]
|
||||
#[help("for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html")]
|
||||
pub(crate) struct UndefinedTransmuteLint;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::ops::ControlFlow;
|
|||
use bitflags::bitflags;
|
||||
use rustc_abi::VariantIdx;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::DiagMessage;
|
||||
use rustc_errors::{DiagMessage, inline_fluent};
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::{self as hir, AmbigArg};
|
||||
|
|
@ -21,7 +21,7 @@ use tracing::debug;
|
|||
|
||||
use super::repr_nullable_ptr;
|
||||
use crate::lints::{ImproperCTypes, UsesPowerAlignment};
|
||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
declare_lint! {
|
||||
/// The `improper_ctypes` lint detects incorrect use of types in foreign
|
||||
|
|
@ -158,12 +158,12 @@ pub(crate) fn check_non_exhaustive_variant(
|
|||
// with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
|
||||
// but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
|
||||
if variant_has_complex_ctor(variant) {
|
||||
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive);
|
||||
return ControlFlow::Break(inline_fluent!("this enum is non-exhaustive"));
|
||||
}
|
||||
}
|
||||
|
||||
if variant.field_list_has_applicable_non_exhaustive() {
|
||||
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant);
|
||||
return ControlFlow::Break(inline_fluent!("this enum has non-exhaustive variants"));
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
|
|
@ -424,7 +424,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
if all_phantom {
|
||||
FfiPhantom(ty)
|
||||
} else if transparent_with_all_zst_fields {
|
||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
|
||||
FfiUnsafe {
|
||||
ty,
|
||||
reason: inline_fluent!("this struct contains only zero-sized fields"),
|
||||
help: None,
|
||||
}
|
||||
} else {
|
||||
FfiSafe
|
||||
}
|
||||
|
|
@ -460,7 +464,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
} else {
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_box,
|
||||
reason: inline_fluent!("box cannot be represented as a single pointer"),
|
||||
help: None,
|
||||
};
|
||||
}
|
||||
|
|
@ -476,8 +480,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
{
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_cstr_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_cstr_help),
|
||||
reason: inline_fluent!(
|
||||
"`CStr`/`CString` do not have a guaranteed layout"
|
||||
),
|
||||
help: Some(inline_fluent!(
|
||||
"consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`"
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -485,14 +493,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: if def.is_struct() {
|
||||
fluent::lint_improper_ctypes_struct_layout_reason
|
||||
inline_fluent!("this struct has unspecified layout")
|
||||
} else {
|
||||
fluent::lint_improper_ctypes_union_layout_reason
|
||||
inline_fluent!("this union has unspecified layout")
|
||||
},
|
||||
help: if def.is_struct() {
|
||||
Some(fluent::lint_improper_ctypes_struct_layout_help)
|
||||
Some(inline_fluent!(
|
||||
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"
|
||||
))
|
||||
} else {
|
||||
Some(fluent::lint_improper_ctypes_union_layout_help)
|
||||
Some(inline_fluent!(
|
||||
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"
|
||||
))
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -501,9 +513,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: if def.is_struct() {
|
||||
fluent::lint_improper_ctypes_struct_non_exhaustive
|
||||
inline_fluent!("this struct is non-exhaustive")
|
||||
} else {
|
||||
fluent::lint_improper_ctypes_union_non_exhaustive
|
||||
inline_fluent!("this union is non-exhaustive")
|
||||
},
|
||||
help: None,
|
||||
};
|
||||
|
|
@ -513,14 +525,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: if def.is_struct() {
|
||||
fluent::lint_improper_ctypes_struct_fieldless_reason
|
||||
inline_fluent!("this struct has no fields")
|
||||
} else {
|
||||
fluent::lint_improper_ctypes_union_fieldless_reason
|
||||
inline_fluent!("this union has no fields")
|
||||
},
|
||||
help: if def.is_struct() {
|
||||
Some(fluent::lint_improper_ctypes_struct_fieldless_help)
|
||||
Some(inline_fluent!("consider adding a member to this struct"))
|
||||
} else {
|
||||
Some(fluent::lint_improper_ctypes_union_fieldless_help)
|
||||
Some(inline_fluent!("consider adding a member to this union"))
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -545,8 +557,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_enum_repr_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_enum_repr_help),
|
||||
reason: inline_fluent!("enum has no representation hint"),
|
||||
help: Some(inline_fluent!(
|
||||
"consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -572,8 +586,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
|
||||
ty::Char => FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_char_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_char_help),
|
||||
reason: inline_fluent!("the `char` type has no C equivalent"),
|
||||
help: Some(inline_fluent!("consider using `u32` or `libc::wchar_t` instead")),
|
||||
},
|
||||
|
||||
// It's just extra invariants on the type that you need to uphold,
|
||||
|
|
@ -585,24 +599,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
|
||||
ty::Slice(_) => FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_slice_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_slice_help),
|
||||
reason: inline_fluent!("slices have no C equivalent"),
|
||||
help: Some(inline_fluent!("consider using a raw pointer instead")),
|
||||
},
|
||||
|
||||
ty::Dynamic(..) => {
|
||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
|
||||
}
|
||||
ty::Dynamic(..) => FfiUnsafe {
|
||||
ty,
|
||||
reason: inline_fluent!("trait objects have no C equivalent"),
|
||||
help: None,
|
||||
},
|
||||
|
||||
ty::Str => FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_str_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_str_help),
|
||||
reason: inline_fluent!("string slices have no C equivalent"),
|
||||
help: Some(inline_fluent!("consider using `*const u8` and a length instead")),
|
||||
},
|
||||
|
||||
ty::Tuple(..) => FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_tuple_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_tuple_help),
|
||||
reason: inline_fluent!("tuples have unspecified layout"),
|
||||
help: Some(inline_fluent!("consider using a struct instead")),
|
||||
},
|
||||
|
||||
ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
|
||||
|
|
@ -632,8 +648,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
if sig.abi().is_rustic_abi() {
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_fnptr_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_fnptr_help),
|
||||
reason: inline_fluent!(
|
||||
"this function pointer has Rust-specific calling convention"
|
||||
),
|
||||
help: Some(inline_fluent!(
|
||||
"consider using an `extern fn(...) -> ...` function pointer instead"
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -657,9 +677,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
|
||||
// While opaque types are checked for earlier, if a projection in a struct field
|
||||
// normalizes to an opaque type, then it will reach this branch.
|
||||
ty::Alias(ty::Opaque, ..) => {
|
||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
|
||||
}
|
||||
ty::Alias(ty::Opaque, ..) => FfiUnsafe {
|
||||
ty,
|
||||
reason: inline_fluent!("opaque types have no C equivalent"),
|
||||
help: None,
|
||||
},
|
||||
|
||||
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
|
||||
// so they are currently ignored for the purposes of this lint.
|
||||
|
|
@ -669,9 +691,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
FfiSafe
|
||||
}
|
||||
|
||||
ty::UnsafeBinder(_) => {
|
||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_unsafe_binder, help: None }
|
||||
}
|
||||
ty::UnsafeBinder(_) => FfiUnsafe {
|
||||
ty,
|
||||
reason: inline_fluent!(
|
||||
"unsafe binders are incompatible with foreign function interfaces"
|
||||
),
|
||||
help: None,
|
||||
},
|
||||
|
||||
ty::Param(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
|
||||
|
|
@ -715,7 +741,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
{
|
||||
Some(FfiResult::FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_opaque,
|
||||
reason: inline_fluent!("opaque types have no C equivalent"),
|
||||
help: None,
|
||||
})
|
||||
} else {
|
||||
|
|
@ -728,8 +754,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
if let ty::Array(..) = ty.kind() {
|
||||
Some(FfiResult::FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_array_reason,
|
||||
help: Some(fluent::lint_improper_ctypes_array_help),
|
||||
reason: inline_fluent!("passing raw arrays by value is not FFI-safe"),
|
||||
help: Some(inline_fluent!("consider passing a pointer to the array")),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
|
@ -908,7 +934,7 @@ impl<'tcx> ImproperCTypesLint {
|
|||
cx,
|
||||
ty,
|
||||
sp,
|
||||
fluent::lint_improper_ctypes_only_phantomdata,
|
||||
inline_fluent!("composed only of `PhantomData`"),
|
||||
None,
|
||||
fn_mode,
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue