diff options
346 files changed, 6440 insertions, 2117 deletions
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..ca704082a3f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,10 @@ +<!-- +If this PR is related to an unstable feature or an otherwise tracked effort, +please link to the relevant tracking issue here. If you don't know of a related +tracking issue or there are none, feel free to ignore this. + +This PR will get automatically assigned to a reviewer. In case you would like +a specific user to review your work, you can assign it to them by using + + r? <reviewer name> +--> \ No newline at end of file diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index a3731e94276..31a184fe921 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -55,9 +55,6 @@ ast_passes_const_without_body = ast_passes_constraint_on_negative_bound = associated type constraints not allowed on negative bounds -ast_passes_deprecated_where_clause_location = - where clause not allowed here - ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses .label = not supported .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax @@ -80,8 +77,6 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de .suggestion = remove the {$remove_descr} .label = `extern` block begins here -ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated - ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel .suggestion = remove the attribute .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 9d07683f8d6..c57be3cdf35 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -27,7 +27,6 @@ use std::ops::{Deref, DerefMut}; use thin_vec::thin_vec; use crate::errors; -use crate::fluent_generated as fluent; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { @@ -766,11 +765,10 @@ impl<'a> AstValidator<'a> { .span_to_snippet(span) .is_ok_and(|snippet| !snippet.starts_with("#[")) { - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( MISSING_ABI, id, span, - fluent::ast_passes_extern_without_abi, BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK), ) } @@ -1428,17 +1426,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { - let msg = match ctxt { - FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign, - _ => fluent::ast_passes_pattern_in_bodiless, - }; - let diag = BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident); - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( PATTERNS_IN_FNS_WITHOUT_BODY, id, span, - msg, - diag, + BuiltinLintDiag::PatternsInFnsWithoutBody { + span, + ident, + is_foreign: matches!(ctxt, FnCtxt::Foreign), + }, ) } } else { @@ -1510,12 +1506,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { Some((right, snippet)) } }; - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( DEPRECATED_WHERE_CLAUSE_LOCATION, item.id, err.span, - fluent::ast_passes_deprecated_where_clause_location, - BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg), + BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg), ); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 25a125f8393..a95a7bdaf6d 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -669,6 +669,7 @@ pub struct ConstAndCVariadic { #[derive(Diagnostic)] #[diag(ast_passes_pattern_in_foreign, code = E0130)] +// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`) pub struct PatternInForeign { #[primary_span] #[label] @@ -677,6 +678,7 @@ pub struct PatternInForeign { #[derive(Diagnostic)] #[diag(ast_passes_pattern_in_bodiless, code = E0642)] +// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`) pub struct PatternInBodiless { #[primary_span] #[label] diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index c08bf287733..5113c5adc8f 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -528,15 +528,10 @@ pub fn cfg_matches( try_gate_cfg(cfg.name, cfg.span, sess, features); match sess.psess.check_config.expecteds.get(&cfg.name) { Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => { - sess.psess.buffer_lint_with_diagnostic( + sess.psess.buffer_lint( UNEXPECTED_CFGS, cfg.span, lint_node_id, - if let Some(value) = cfg.value { - format!("unexpected `cfg` condition value: `{value}`") - } else { - format!("unexpected `cfg` condition value: (none)") - }, BuiltinLintDiag::UnexpectedCfgValue( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), @@ -544,11 +539,10 @@ pub fn cfg_matches( ); } None if sess.psess.check_config.exhaustive_names => { - sess.psess.buffer_lint_with_diagnostic( + sess.psess.buffer_lint( UNEXPECTED_CFGS, cfg.span, lint_node_id, - format!("unexpected `cfg` condition name: `{}`", cfg.name), BuiltinLintDiag::UnexpectedCfgName( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 0f158990319..a3d6a1c7360 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -247,5 +247,3 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal .label = not a trait .str_lit = try using `#[derive({$sym})]` .other = for example, write `#[derive(Debug)]` for `Debug` - -builtin_macros_unnameable_test_items = cannot test inner items diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 49b1b8cf992..1a7961bf70c 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,6 +1,7 @@ use crate::errors; use crate::util::expr_to_spanned_string; use ast::token::IdentIsRaw; +use lint::BuiltinLintDiag; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter}; @@ -513,7 +514,7 @@ fn expand_preparsed_asm( lint::builtin::BAD_ASM_STYLE, find_span(".intel_syntax"), ecx.current_expansion.lint_node_id, - "avoid using `.intel_syntax`, Intel syntax is the default", + BuiltinLintDiag::AvoidUsingIntelSyntax, ); } if template_str.contains(".att_syntax") { @@ -521,7 +522,7 @@ fn expand_preparsed_asm( lint::builtin::BAD_ASM_STYLE, find_span(".att_syntax"), ecx.current_expansion.lint_node_id, - "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead", + BuiltinLintDiag::AvoidUsingAttSyntax, ); } } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 46949f731aa..217fa5ff9f1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1621,14 +1621,13 @@ impl<'a> TraitDef<'a> { }; if let Some(ty) = exception { - cx.sess.psess.buffer_lint_with_diagnostic( + cx.sess.psess.buffer_lint( BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, sp, ast::CRATE_NODE_ID, - format!( - "{ty} slice in a packed struct that derives a built-in trait" - ), - rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive, + rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive { + ty: ty.to_string(), + }, ); } else { // Wrap the expression in `{...}`, causing a copy. diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index a5fc74f1d66..5cb0407bd59 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -556,7 +556,6 @@ fn make_format_args( let arg_name = args.explicit_args()[index].kind.ident().unwrap(); ecx.buffered_early_lint.push(BufferedEarlyLint { span: arg_name.span.into(), - msg: format!("named argument `{}` is not used by name", arg_name.name).into(), node_id: rustc_ast::CRATE_NODE_ID, lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY), diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally { diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 47b2ee975ca..29e991525a9 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -11,6 +11,7 @@ use rustc_expand::base::{ resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, }; use rustc_expand::module::DirOwnership; +use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; @@ -147,7 +148,7 @@ pub(crate) fn expand_include<'cx>( INCOMPLETE_INCLUDE, self.p.token.span, self.node_id, - "include macro expected single expression in source", + BuiltinLintDiag::IncompleteInclude, ); } Some(expr) diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 8cf431482ff..38ac2f15fe7 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -9,6 +9,7 @@ use rustc_ast::{attr, ModKind}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; +use rustc_lint_defs::BuiltinLintDiag; use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS; use rustc_session::Session; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; @@ -163,7 +164,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> { UNNAMEABLE_TEST_ITEMS, attr.span, i.id, - crate::fluent_generated::builtin_macros_unnameable_test_items, + BuiltinLintDiag::UnnameableTestItems, ); } } diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 8dc7bc14ec3..652e34268ea 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -5,7 +5,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt}; use rustc_expand::expand::AstFragment; use rustc_feature::AttributeTemplate; -use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; +use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag}; use rustc_parse::{parser, validate_attr}; use rustc_session::errors::report_lit_error; use rustc_span::{BytePos, Span, Symbol}; @@ -46,7 +46,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, DUPLICATE_MACRO_ATTRIBUTES, attr.span, ecx.current_expansion.lint_node_id, - "duplicated attribute", + BuiltinLintDiag::DuplicateMacroAttribute, ); } } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 4bf7dccab92..662c8a7b8be 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -282,6 +282,12 @@ impl IntoDiagArg for ClosureKind { } } +impl IntoDiagArg for hir::def::Namespace { + fn into_diag_arg(self) -> DiagArgValue { + DiagArgValue::Str(Cow::Borrowed(self.descr())) + } +} + #[derive(Clone)] pub struct DiagSymbolList(Vec<Symbol>); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 12868a66605..91af8758e51 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1364,18 +1364,15 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool { }; if crate_matches { - // FIXME: make this translatable - #[allow(rustc::untranslatable_diagnostic)] - sess.psess.buffer_lint_with_diagnostic( - PROC_MACRO_BACK_COMPAT, - item.ident.span, - ast::CRATE_NODE_ID, - "using an old version of `rental`", - BuiltinLintDiag::ProcMacroBackCompat( - "older versions of the `rental` crate will stop compiling in future versions of Rust; \ - please update to `rental` v0.5.6, or switch to one of the `rental` alternatives".to_string() - ) - ); + sess.psess.buffer_lint( + PROC_MACRO_BACK_COMPAT, + item.ident.span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::ProcMacroBackCompat { + crate_name: "rental".to_string(), + fixed_version: "0.5.6".to_string(), + }, + ); return true; } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 35f0d8abffc..badfa6d3aa3 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -14,6 +14,7 @@ use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::Features; use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES}; +use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -248,7 +249,6 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> { let Some((cfg_predicate, expanded_attrs)) = rustc_parse::parse_cfg_attr(attr, &self.sess.psess) @@ -262,7 +262,7 @@ impl<'a> StripUnconfigured<'a> { rustc_lint_defs::builtin::UNUSED_ATTRIBUTES, attr.span, ast::CRATE_NODE_ID, - "`#[cfg_attr]` does not expand to any attributes", + BuiltinLintDiag::CfgAttrNoAttributes, ); } @@ -283,7 +283,6 @@ impl<'a> StripUnconfigured<'a> { } } - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable fn expand_cfg_attr_item( &self, attr: &Attribute, @@ -346,7 +345,7 @@ impl<'a> StripUnconfigured<'a> { rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, attr.span, ast::CRATE_NODE_ID, - "`crate_type` within an `#![cfg_attr] attribute is deprecated`", + BuiltinLintDiag::CrateTypeInCfgAttr, ); } if attr.has_name(sym::crate_name) { @@ -354,7 +353,7 @@ impl<'a> StripUnconfigured<'a> { rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, attr.span, ast::CRATE_NODE_ID, - "`crate_name` within an `#![cfg_attr] attribute is deprecated`", + BuiltinLintDiag::CrateNameInCfgAttr, ); } attr diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index a049ac251e1..d8f0f221189 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1799,11 +1799,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } if attr.is_doc_comment() { - self.cx.sess.psess.buffer_lint_with_diagnostic( + self.cx.sess.psess.buffer_lint( UNUSED_DOC_COMMENTS, current_span, self.cx.current_expansion.lint_node_id, - "unused doc comment", BuiltinLintDiag::UnusedDocComment(attr.span), ); } else if rustc_attr::is_builtin_attr(attr) { @@ -1811,11 +1810,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { // `#[cfg]` and `#[cfg_attr]` are special - they are // eagerly evaluated. if attr_name != sym::cfg && attr_name != sym::cfg_attr { - self.cx.sess.psess.buffer_lint_with_diagnostic( + self.cx.sess.psess.buffer_lint( UNUSED_ATTRIBUTES, attr.span, self.cx.current_expansion.lint_node_id, - format!("unused attribute `{attr_name}`"), BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name: pprust::path_to_string(&call.path), diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index dce8e0c36ed..72dbbde54b3 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -110,7 +110,8 @@ use crate::mbe::{KleeneToken, TokenTree}; use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{DiagMessage, MultiSpan}; +use rustc_errors::MultiSpan; +use rustc_lint_defs::BuiltinLintDiag; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; @@ -252,7 +253,7 @@ fn check_binders( // 1. The meta-variable is already bound in the current LHS: This is an error. let mut span = MultiSpan::from_span(span); span.push_span_label(prev_info.span, "previous declaration"); - buffer_lint(psess, span, node_id, "duplicate matcher binding"); + buffer_lint(psess, span, node_id, BuiltinLintDiag::DuplicateMatcherBinding); } else if get_binder_info(macros, binders, name).is_none() { // 2. The meta-variable is free: This is a binder. binders.insert(name, BinderInfo { span, ops: ops.into() }); @@ -271,7 +272,7 @@ fn check_binders( MISSING_FRAGMENT_SPECIFIER, span, node_id, - "missing fragment specifier", + BuiltinLintDiag::MissingFragmentSpecifier, ); } if !macros.is_empty() { @@ -595,7 +596,7 @@ fn check_ops_is_prefix( return; } } - buffer_lint(psess, span.into(), node_id, format!("unknown macro variable `{name}`")); + buffer_lint(psess, span.into(), node_id, BuiltinLintDiag::UnknownMacroVariable(name)); } /// Returns whether `binder_ops` is a prefix of `occurrence_ops`. @@ -628,8 +629,7 @@ fn ops_is_prefix( if i >= occurrence_ops.len() { let mut span = MultiSpan::from_span(span); span.push_span_label(binder.span, "expected repetition"); - let message = format!("variable '{name}' is still repeating at this depth"); - buffer_lint(psess, span, node_id, message); + buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableStillRepeating(name)); return; } let occurrence = &occurrence_ops[i]; @@ -637,21 +637,15 @@ fn ops_is_prefix( let mut span = MultiSpan::from_span(span); span.push_span_label(binder.span, "expected repetition"); span.push_span_label(occurrence.span, "conflicting repetition"); - let message = "meta-variable repeats with different Kleene operator"; - buffer_lint(psess, span, node_id, message); + buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableWrongOperator); return; } } } -fn buffer_lint( - psess: &ParseSess, - span: MultiSpan, - node_id: NodeId, - message: impl Into<DiagMessage>, -) { +fn buffer_lint(psess: &ParseSess, span: MultiSpan, node_id: NodeId, diag: BuiltinLintDiag) { // Macros loaded from other crates have dummy node ids. if node_id != DUMMY_NODE_ID { - psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, message); + psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, diag); } } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8f18055f838..d99ecb61085 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -79,11 +79,10 @@ impl<'a> ParserAnyMacro<'a> { // but `m!()` is allowed in expression positions (cf. issue #34706). if kind == AstFragmentKind::Expr && parser.token == token::Semi { if is_local { - parser.psess.buffer_lint_with_diagnostic( + parser.psess.buffer_lint( SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, parser.token.span, lint_node_id, - "trailing semicolon in macro used in expression position", BuiltinLintDiag::TrailingMacro(is_trailing_mac, macro_ident), ); } @@ -1154,11 +1153,10 @@ fn check_matcher_core<'tt>( name, Some(NonterminalKind::PatParam { inferred: false }), )); - sess.psess.buffer_lint_with_diagnostic( + sess.psess.buffer_lint( RUST_2021_INCOMPATIBLE_OR_PATTERNS, span, ast::CRATE_NODE_ID, - "the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro", BuiltinLintDiag::OrPatternsBackCompat(span, suggestion), ); } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index ce2382b9501..987e48a1a76 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -399,31 +399,17 @@ pub(crate) fn check_attr_crate_type( if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() { let span = spanned.span; - let lev_candidate = find_best_match_for_name( + let candidate = find_best_match_for_name( &CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(), n, None, ); - if let Some(candidate) = lev_candidate { - lint_buffer.buffer_lint_with_diagnostic( - lint::builtin::UNKNOWN_CRATE_TYPES, - ast::CRATE_NODE_ID, - span, - "invalid `crate_type` value", - BuiltinLintDiag::UnknownCrateTypes( - span, - "did you mean".to_string(), - format!("\"{candidate}\""), - ), - ); - } else { - lint_buffer.buffer_lint( - lint::builtin::UNKNOWN_CRATE_TYPES, - ast::CRATE_NODE_ID, - span, - "invalid `crate_type` value", - ); - } + lint_buffer.buffer_lint( + lint::builtin::UNKNOWN_CRATE_TYPES, + ast::CRATE_NODE_ID, + span, + BuiltinLintDiag::UnknownCrateTypes { span, candidate }, + ); } } else { // This is here mainly to check for using a macro, such as diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index cf9d089ff62..6f6480a4964 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -1,7 +1,20 @@ +lint_abs_path_with_module = absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + .suggestion = use `crate` + +lint_ambiguous_glob_reexport = ambiguous glob re-exports + .label_first_reexport = the name `{$name}` in the {$namespace} namespace is first re-exported here + .label_duplicate_reexport = but the name `{$name}` in the {$namespace} namespace is also re-exported here + lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +lint_associated_const_elided_lifetime = {$elided -> + [true] `&` without an explicit lifetime name cannot be used here + *[false] `'_` cannot be used here + } + .suggestion = use the `'static` lifetime + lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` .suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change @@ -19,10 +32,19 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` +lint_avoid_att_syntax = + avoid using `.att_syntax`, prefer using `options(att_syntax)` instead + +lint_avoid_intel_syntax = + avoid using `.intel_syntax`, Intel syntax is the default + lint_bad_attribute_argument = bad attribute argument lint_bad_opt_access = {$msg} +lint_break_with_label_and_loop = this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression + .suggestion = wrap this expression in parentheses + lint_builtin_allow_internal_unsafe = `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site @@ -30,6 +52,8 @@ lint_builtin_anonymous_params = anonymous parameters are deprecated and will be .suggestion = try naming the parameter or explicitly ignoring it lint_builtin_asm_labels = avoid using named labels in inline assembly + .help = only local labels of the form `<number>:` should be used in inline asm + .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty} @@ -154,6 +178,12 @@ lint_builtin_unused_doc_comment = unused doc comment lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` +lint_byte_slice_in_packed_struct_with_derive = {$ty} slice in a packed struct that derives a built-in trait + .help = consider implementing the trait by hand, or remove the `packed` attribute + +lint_cfg_attr_no_attributes = + `#[cfg_attr]` does not expand to any attributes + lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` lint_command_line_source = `forbid` lint level was set on command line @@ -162,12 +192,20 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i .current_use = this identifier can be confused with `{$existing_sym}` .other_use = other identifier used here +lint_crate_name_in_cfg_attr_deprecated = + `crate_name` within an `#![cfg_attr]` attribute is deprecated + +lint_crate_type_in_cfg_attr_deprecated = + `crate_type` within an `#![cfg_attr]` attribute is deprecated + lint_cstring_ptr = getting the inner pointer of a temporary `CString` .as_ptr_label = this pointer will be invalid .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned .help = for more information, see https://doc.rust-lang.org/reference/destructors.html +lint_custom_inner_attribute_unstable = custom inner attributes are unstable + lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary @@ -178,6 +216,11 @@ lint_deprecated_lint_name = .suggestion = change it to .help = change it to {$replace} +lint_deprecated_where_clause_location = where clause not allowed here + .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information + .suggestion_move_to_end = move it to the end of the type declaration + .suggestion_remove_where = remove this `where` + lint_diag_out_of_impl = diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls @@ -195,6 +238,11 @@ lint_dropping_references = calls to `std::mem::drop` with a reference instead of .label = argument has type `{$arg_ty}` .note = use `let _ = ...` to ignore the expression or result +lint_duplicate_macro_attribute = + duplicated attribute + +lint_duplicate_matcher_binding = duplicate matcher binding + lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. @@ -207,6 +255,13 @@ lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message .rationale = {$rationale} +lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition + .suggestion = convert it to a `use` + +lint_extern_without_abi = extern declarations without an explicit ABI are deprecated + .label = ABI should be specified here + .help = the default ABI is {$default_abi} + lint_for_loops_over_fallibles = for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement .suggestion = consider using `if let` to clear intent @@ -221,6 +276,12 @@ lint_forgetting_references = calls to `std::mem::forget` with a reference instea .label = argument has type `{$arg_ty}` .note = use `let _ = ...` to ignore the expression or result +lint_hidden_glob_reexport = private item shadows public glob re-export + .note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here + .note_private_item = but the private item here shadows it + +lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated + lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> [one] an invisible @@ -262,6 +323,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len -> lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level +lint_ill_formed_attribute_input = {$num_suggestions -> + [1] attribute must be of the form {$suggestions} + *[other] valid forms for the attribute are {$suggestions} + } + lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than possibly intended in edition 2024 .note = specifically, {$num_captured -> [one] this lifetime is @@ -332,6 +398,14 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +lint_incomplete_include = + include macro expected single expression in source + +lint_inner_macro_attribute_unstable = inner macro attributes are unstable + +lint_invalid_crate_type_value = invalid `crate_type` value + .suggestion = did you mean + # FIXME: we should ordinalize $valid_up_to when we add support for doing so lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes @@ -360,9 +434,22 @@ lint_invalid_reference_casting_note_book = for more information, visit <https:// lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get` +lint_legacy_derive_helpers = derive helper attribute is used before it is introduced + .label = the attribute is introduced here + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead +lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths + .note = the macro is defined here + +lint_macro_is_private = macro `{$ident}` is private + +lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used + +lint_macro_use_deprecated = + deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead + lint_malformed_attribute = malformed lint attribute input lint_map_unit_fn = `Iterator::map` call that discard the iterator's values @@ -372,6 +459,12 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items .suggestion = you might have meant to use `Iterator::for_each` +lint_metavariable_still_repeating = variable '{$name}' is still repeating at this depth + +lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator + +lint_missing_fragment_specifier = missing fragment specifier + lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes_note = the usage includes {$includes} @@ -379,6 +472,11 @@ lint_mixed_script_confusables = lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits +lint_named_argument_used_positionally = named argument `{$named_arg_name}` is not used by name + .label_named_arg = this named argument is referred to by position in formatting string + .label_position_arg = this formatting argument uses named argument `{$named_arg_name}` by position + .suggestion = use the named argument by name to avoid ambiguity + lint_node_source = `forbid` level set here .note = {$reason} @@ -490,6 +588,9 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass lint_opaque_hidden_inferred_bound_sugg = add this bound +lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + .suggestion = use pat_param to preserve semantics + lint_overflowing_bin_hex = literal out of range for `{$ty}` .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` @@ -519,6 +620,21 @@ lint_path_statement_drop = path statement drops value lint_path_statement_no_effect = path statement with no effect +lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies + .label = pattern not allowed in function without body + +lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations + .label = pattern not allowed in foreign function + +lint_private_extern_crate_reexport = + extern crate `{$ident}` is private, and cannot be re-exported (error E0365), consider declaring with `pub` + +lint_proc_macro_back_compat = using an old version of `{$crate_name}` + .note = older versions of the `{$crate_name}` crate will stop compiling in future versions of Rust; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives + +lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope + .label = names from parent modules are not accessible without an explicit import + lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value .label = expression has type `{$orig_ty}` @@ -540,6 +656,16 @@ lint_reason_must_be_string_literal = reason must be a string literal lint_reason_must_come_last = reason in lint attribute must come last +lint_redundant_import = the item `{$ident}` is imported redundantly + .label_imported_here = the item `{ident}` is already imported here + .label_defined_here = the item `{ident}` is already defined here + .label_imported_prelude = the item `{ident}` is already imported by the extern prelude + .label_defined_prelude = the item `{ident}` is already defined by the extern prelude + +lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough + .note = the most public imported item is `{$max_vis}` + .help = reduce the glob import's visibility or increase visibility of imported items + lint_redundant_semicolons = unnecessary trailing {$multiple -> [true] semicolons @@ -550,6 +676,8 @@ lint_redundant_semicolons = *[false] this semicolon } +lint_remove_mut_from_pattern = remove `mut` from the parameter + lint_removed_lint = lint `{$name}` has been removed: {$reason} lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}` @@ -558,6 +686,10 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}` lint_requested_level = requested on the command line with `{$level} {$lint_name}` +lint_reserved_prefix = prefix `{$prefix}` is unknown + .label = unknown prefix + .suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + lint_shadowed_into_iter = this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition} .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity @@ -565,6 +697,11 @@ lint_shadowed_into_iter = .use_explicit_into_iter_suggestion = or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value +lint_single_use_lifetime = lifetime parameter `{$ident}` only used once + .label_param = this lifetime... + .label_use = ...is used only here + .suggestion = elide the single-use lifetime + lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion @@ -578,6 +715,10 @@ lint_suspicious_double_ref_clone = lint_suspicious_double_ref_deref = using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type +lint_trailing_semi_macro = trailing semicolon in macro used in expression position + .note1 = macro invocations at the end of a block are treated as expressions + .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` + lint_ty_qualified = usage of qualified `ty::{$ty}` .suggestion = try importing it and using it unqualified @@ -591,12 +732,64 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value +lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs` +lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead +lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} +lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}` +lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` +lint_unexpected_cfg_doc_cargo = see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration +lint_unexpected_cfg_doc_rustc = see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration + +lint_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}` +lint_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more -> + [0] {""} + *[other] {" "}and {$and_more} more + } +lint_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities} +lint_unexpected_cfg_name_similar_name = there is a config with a similar name +lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values +lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value +lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value +lint_unexpected_cfg_name_with_similar_value = found config with similar value + +lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value -> + [true] `{$value}` + *[false] (none) + } +lint_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml` +lint_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility -> + [true] {"(none), "} + *[false] {""} + }{$possibilities}{$and_more -> + [0] {""} + *[other] {" "}and {$and_more} more + } +lint_unexpected_cfg_value_no_expected_value = no expected value for `{$name}` +lint_unexpected_cfg_value_no_expected_values = no expected values for `{$name}` +lint_unexpected_cfg_value_remove_condition = remove the condition +lint_unexpected_cfg_value_remove_value = remove the value +lint_unexpected_cfg_value_similar_name = there is a expected value with a similar name +lint_unexpected_cfg_value_specify_value = specify a config value + lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op .label = this function will not propagate the caller location +lint_unicode_text_flow = unicode codepoint changing visible direction of text present in comment + .label = {$num_codepoints -> + [1] this comment contains an invisible unicode text flow control codepoint + *[other] this comment contains invisible unicode text flow control codepoints + } + .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + .suggestion = if their presence wasn't intentional, you can remove them + .label_comment_char = {$c_debug} + + lint_unit_bindings = binding has unit type `()` .label = this pattern is inferred to be the unit type `()` +lint_unknown_diagnostic_attribute = unknown diagnostic attribute +lint_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists + lint_unknown_gated_lint = unknown lint: `{$name}` .note = the `{$name}` lint is unstable @@ -612,9 +805,16 @@ lint_unknown_lint = *[false] did you mean: `{$replace}` } +lint_unknown_macro_variable = unknown macro variable `{$name}` + lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` .help = add `#![register_tool({$tool_name})]` to the crate root +lint_unnameable_test_items = cannot test inner items + +lint_unnecessary_qualification = unnecessary qualification + .suggestion = remove the unnecessary path segments + lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ lint_untranslatable_diag = diagnostics should be created using translatable messages @@ -622,6 +822,9 @@ lint_untranslatable_diag = diagnostics should be created using translatable mess lint_unused_allocation = unnecessary allocation, use `&` instead lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead +lint_unused_builtin_attribute = unused attribute `{$attr_name}` + .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}` + lint_unused_closure = unused {$pre}{$count -> [one] closure @@ -638,14 +841,43 @@ lint_unused_coroutine = }{$post} that must be used .note = coroutines are lazy and do nothing unless resumed +lint_unused_crate_dependency = external crate `{$extern_crate}` unused in `{$local_crate}`: remove the dependency or add `use {$extern_crate} as _;` + lint_unused_def = unused {$pre}`{$def}`{$post} that must be used .suggestion = use `let _ = ...` to ignore the resulting value lint_unused_delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} +lint_unused_doc_comment = unused doc comment + .label = rustdoc does not generate documentation for macro invocations + .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion + +lint_unused_extern_crate = unused extern crate + .suggestion = remove it + lint_unused_import_braces = braces around {$node} is unnecessary +lint_unused_imports = {$num_snippets -> + [one] unused import: {$span_snippets} + *[other] unused imports: {$span_snippets} + } + .suggestion_remove_whole_use = remove the whole `use` item + .suggestion_remove_imports = {$num_to_remove -> + [one] remove the unused import + *[other] remove the unused imports + } + .help = if this is a test module, consider adding a `#[cfg(test)]` to the containing module + +lint_unused_label = unused label + +lint_unused_lifetime = lifetime parameter `{$ident}` never used + .suggestion = elide the unused lifetime + +lint_unused_macro_definition = unused macro definition: `{$name}` + +lint_unused_macro_use = unused `#[macro_use]` import + lint_unused_op = unused {$op} that must be used .label = the {$op} produces a value .suggestion = use `let _ = ...` to ignore the resulting value @@ -654,3 +886,6 @@ lint_unused_result = unused result of type `{$ty}` lint_variant_size_differences = enum variant is more than three times larger ({$largest} bytes) than the next largest + +lint_wasm_c_abi = + older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88 diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6b9f9d1531e..0f059bceae7 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -30,10 +30,10 @@ use crate::{ BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, - BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, - BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, - BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, - BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, + BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric, + BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, + BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion, + BuiltinTypeAliasWhereClause, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, SuggestChangingAssocTypes, @@ -60,7 +60,7 @@ use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::Upcast; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; -use rustc_session::lint::{BuiltinLintDiag, FutureIncompatibilityReason}; +use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; @@ -2882,16 +2882,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { let target_spans: MultiSpan = if spans.len() > 0 { spans.into() } else { (*template_span).into() }; - cx.span_lint_with_diagnostics( - NAMED_ASM_LABELS, - Some(target_spans), - fluent::lint_builtin_asm_labels, - |_| {}, - BuiltinLintDiag::NamedAsmLabel( - "only local labels of the form `<number>:` should be used in inline asm" - .to_string(), - ), - ); + cx.emit_span_lint(NAMED_ASM_LABELS, target_spans, BuiltinNamedAsmLabel); } } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 62ba9ef5c11..deeb3ae090c 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -527,30 +527,24 @@ pub struct EarlyContext<'a> { pub buffered: LintBuffer, } -pub trait LintContext { - fn sess(&self) -> &Session; - +impl EarlyContext<'_> { /// Emit a lint at the appropriate level, with an optional associated span and an existing /// diagnostic. /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] - fn span_lint_with_diagnostics( + pub fn span_lint_with_diagnostics( &self, lint: &'static Lint, - span: Option<impl Into<MultiSpan>>, - msg: impl Into<DiagMessage>, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), + span: MultiSpan, diagnostic: BuiltinLintDiag, ) { - // We first generate a blank diagnostic. - self.opt_span_lint(lint, span, msg, |db| { - // Now, set up surrounding context. - diagnostics::builtin(self.sess(), diagnostic, db); - // Rewrap `db`, and pass control to the user. - decorate(db) - }); + diagnostics::emit_buffered_lint(self, lint, span, diagnostic) } +} + +pub trait LintContext { + fn sess(&self) -> &Session; // FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to // set the span in their `decorate` function (preferably using set_span). diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 5ad3ff71a6d..236eeee6152 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -1,58 +1,57 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +use std::borrow::Cow; + use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; -use rustc_errors::{elided_lifetime_in_path_suggestion, Diag}; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; +use rustc_errors::{elided_lifetime_in_path_suggestion, DiagArgValue, MultiSpan}; use rustc_middle::middle::stability; -use rustc_session::lint::BuiltinLintDiag; -use rustc_session::Session; +use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_span::BytePos; +use crate::{lints, EarlyContext, LintContext as _}; + mod check_cfg; -pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) { +pub(super) fn emit_buffered_lint( + ctx: &EarlyContext<'_>, + lint: &'static Lint, + span: MultiSpan, + diagnostic: BuiltinLintDiag, +) { + let sess = ctx.sess(); match diagnostic { - BuiltinLintDiag::UnicodeTextFlow(span, content) => { + BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { let spans: Vec<_> = content .char_indices() .filter_map(|(i, c)| { TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { - let lo = span.lo() + BytePos(2 + i as u32); - (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) + let lo = comment_span.lo() + BytePos(2 + i as u32); + (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) }) }) .collect(); - let (an, s) = match spans.len() { - 1 => ("an ", ""), - _ => ("", "s"), - }; - diag.span_label( + let characters = spans + .iter() + .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") }) + .collect(); + let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion { + spans: spans.iter().map(|(_c, span)| *span).collect(), + }); + ctx.emit_span_lint( + lint, span, - format!( - "this comment contains {an}invisible unicode text flow control codepoint{s}", - ), - ); - for (c, span) in &spans { - diag.span_label(*span, format!("{c:?}")); - } - diag.note( - "these kind of unicode codepoints change the way text flows on \ - applications that support them, but can cause confusion because they \ - change the order of characters on the screen", - ); - if !spans.is_empty() { - diag.multipart_suggestion_with_style( - "if their presence wasn't intentional, you can remove them", - spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(), - Applicability::MachineApplicable, - SuggestionStyle::HideCodeAlways, - ); - } - } - BuiltinLintDiag::Normal => (), - BuiltinLintDiag::AbsPathWithModule(span) => { - let (sugg, app) = match sess.source_map().span_to_snippet(span) { + lints::UnicodeTextFlow { + comment_span, + characters, + suggestions, + num_codepoints: spans.len(), + }, + ) + } + BuiltinLintDiag::AbsPathWithModule(mod_span) => { + let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) { Ok(ref s) => { // FIXME(Manishearth) ideally the emitting code // can tell us whether or not this is global @@ -62,160 +61,207 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di } Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders), }; - diag.span_suggestion(span, "use `crate`", sugg, app); - } - BuiltinLintDiag::ProcMacroDeriveResolutionFallback(span) => { - diag.span_label( + ctx.emit_span_lint( + lint, span, - "names from parent modules are not accessible without an explicit import", + lints::AbsPathWithModule { + sugg: lints::AbsPathWithModuleSugg { + span: mod_span, + applicability, + replacement, + }, + }, ); } - BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => { - diag.span_note(span_def, "the macro is defined here"); - } + BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => ctx + .emit_span_lint( + lint, + span, + lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident }, + ), + BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => ctx + .emit_span_lint( + lint, + span, + lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def }, + ), BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - diag.subdiagnostic( - sess.dcx(), - elided_lifetime_in_path_suggestion( - sess.source_map(), - n, - path_span, - incl_angl_brckt, - insertion_span, - ), + ctx.emit_span_lint( + lint, + span, + lints::ElidedLifetimesInPaths { + subdiag: elided_lifetime_in_path_suggestion( + sess.source_map(), + n, + path_span, + incl_angl_brckt, + insertion_span, + ), + }, ); } - BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => { - diag.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect); - } - BuiltinLintDiag::UnusedImports(message, replaces, in_test_module) => { - if !replaces.is_empty() { - diag.tool_only_multipart_suggestion( - message, - replaces, - Applicability::MachineApplicable, - ); - } + BuiltinLintDiag::UnknownCrateTypes { span, candidate } => { + let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate }); + ctx.emit_span_lint(lint, span, lints::UnknownCrateTypes { sugg }); + } + BuiltinLintDiag::UnusedImports { + remove_whole_use, + num_to_remove, + remove_spans, + test_module_span, + span_snippets, + } => { + let sugg = if remove_whole_use { + lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] } + } else { + lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove } + }; + let test_module_span = + test_module_span.map(|span| sess.source_map().guess_head_span(span)); - if let Some(span) = in_test_module { - diag.span_help( - sess.source_map().guess_head_span(span), - "if this is a test module, consider adding a `#[cfg(test)]` to the containing module", - ); - } + ctx.emit_span_lint( + lint, + span, + lints::UnusedImports { + sugg, + test_module_span, + num_snippets: span_snippets.len(), + span_snippets: DiagArgValue::StrListSepByAnd( + span_snippets.into_iter().map(Cow::Owned).collect(), + ), + }, + ); } BuiltinLintDiag::RedundantImport(spans, ident) => { - for (span, is_imported) in spans { - let introduced = if is_imported { "imported" } else { "defined" }; - let span_msg = if span.is_dummy() { "by the extern prelude" } else { "here" }; - diag.span_label( - span, - format!("the item `{ident}` is already {introduced} {span_msg}"), - ); - } - } - BuiltinLintDiag::DeprecatedMacro(suggestion, span) => { - stability::deprecation_suggestion(diag, "macro", suggestion, span) - } - BuiltinLintDiag::UnusedDocComment(span) => { - diag.span_label(span, "rustdoc does not generate documentation for macro invocations"); - diag.help("to document an item produced by a macro, \ - the macro must produce the documentation as part of its expansion"); - } - BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident) => { - diag.span_suggestion( + let subs = spans + .into_iter() + .map(|(span, is_imported)| { + (match (span.is_dummy(), is_imported) { + (false, true) => lints::RedundantImportSub::ImportedHere, + (false, false) => lints::RedundantImportSub::DefinedHere, + (true, true) => lints::RedundantImportSub::ImportedPrelude, + (true, false) => lints::RedundantImportSub::DefinedPrelude, + })(span) + }) + .collect(); + ctx.emit_span_lint(lint, span, lints::RedundantImport { subs, ident }); + } + BuiltinLintDiag::DeprecatedMacro { + suggestion, + suggestion_span, + note, + path, + since_kind, + } => { + let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion { + span: suggestion_span, + kind: "macro".to_owned(), + suggestion, + }); + ctx.emit_span_lint( + lint, span, - "remove `mut` from the parameter", - ident, - Applicability::MachineApplicable, + stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }, ); } - BuiltinLintDiag::MissingAbi(span, default_abi) => { - diag.span_label(span, "ABI should be specified here"); - diag.help(format!("the default ABI is {}", default_abi.name())); + BuiltinLintDiag::UnusedDocComment(attr_span) => { + ctx.emit_span_lint(lint, span, lints::UnusedDocComment { span: attr_span }); } - BuiltinLintDiag::LegacyDeriveHelpers(span) => { - diag.span_label(span, "the attribute is introduced here"); + BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { + let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; + + ctx.emit_span_lint( + lint, + span, + if is_foreign { + lints::PatternsInFnsWithoutBody::Foreign { sub } + } else { + lints::PatternsInFnsWithoutBody::Bodiless { sub } + }, + ); } - BuiltinLintDiag::ProcMacroBackCompat(note) => { - diag.note(note); + BuiltinLintDiag::MissingAbi(label_span, default_abi) => { + ctx.emit_span_lint( + lint, + span, + lints::MissingAbi { span: label_span, default_abi: default_abi.name() }, + ); } - BuiltinLintDiag::OrPatternsBackCompat(span, suggestion) => { - diag.span_suggestion( + BuiltinLintDiag::LegacyDeriveHelpers(label_span) => { + ctx.emit_span_lint(lint, span, lints::LegacyDeriveHelpers { span: label_span }); + } + BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => { + ctx.emit_span_lint( + lint, span, - "use pat_param to preserve semantics", - suggestion, - Applicability::MachineApplicable, + lints::ProcMacroBackCompat { crate_name, fixed_version }, + ); + } + BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => { + ctx.emit_span_lint( + lint, + span, + lints::OrPatternsBackCompat { span: suggestion_span, suggestion }, ); } - BuiltinLintDiag::ReservedPrefix(span) => { - diag.span_label(span, "unknown prefix"); - diag.span_suggestion_verbose( - span.shrink_to_hi(), - "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", - " ", - Applicability::MachineApplicable, + BuiltinLintDiag::ReservedPrefix(label_span, prefix) => { + ctx.emit_span_lint( + lint, + span, + lints::ReservedPrefix { + label: label_span, + suggestion: label_span.shrink_to_hi(), + prefix, + }, ); } BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => { - diag.span_note( - invoc_span, - format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`") - ); + ctx.emit_span_lint( + lint, + span, + lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }, + ); } BuiltinLintDiag::TrailingMacro(is_trailing, name) => { - if is_trailing { - diag.note("macro invocations at the end of a block are treated as expressions"); - diag.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`")); - } - } - BuiltinLintDiag::BreakWithLabelAndLoop(span) => { - diag.multipart_suggestion( - "wrap this expression in parentheses", - vec![ - (span.shrink_to_lo(), "(".to_string()), - (span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); + ctx.emit_span_lint(lint, span, lints::TrailingMacro { is_trailing, name }); } - BuiltinLintDiag::NamedAsmLabel(help) => { - diag.help(help); - diag.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information"); + BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => { + ctx.emit_span_lint( + lint, + span, + lints::BreakWithLabelAndLoop { + sub: lints::BreakWithLabelAndLoopSub { + left: sugg_span.shrink_to_lo(), + right: sugg_span.shrink_to_hi(), + }, + }, + ); } BuiltinLintDiag::UnexpectedCfgName(name, value) => { - check_cfg::unexpected_cfg_name(sess, diag, name, value) + ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_name(sess, name, value)); } BuiltinLintDiag::UnexpectedCfgValue(name, value) => { - check_cfg::unexpected_cfg_value(sess, diag, name, value) - } - BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg) => { - let left_sp = diag.span.primary_span().unwrap(); - match sugg { - Some((right_sp, sugg)) => diag.multipart_suggestion( - "move it to the end of the type declaration", - vec![(left_sp, String::new()), (right_sp, sugg)], - Applicability::MachineApplicable, - ), - None => diag.span_suggestion( - left_sp, - "remove this `where`", - "", - Applicability::MachineApplicable, - ), + ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_value(sess, name, value)); + } + BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { + let suggestion = match sugg { + Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { + left: left_sp, + right: right_sp, + sugg, + }, + None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, }; - diag.note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information"); + ctx.emit_span_lint(lint, span, lints::DeprecatedWhereClauseLocation { suggestion }); } BuiltinLintDiag::SingleUseLifetime { param_span, use_span: Some((use_span, elide)), deletion_span, + ident, } => { debug!(?param_span, ?use_span, ?deletion_span); - diag.span_label(param_span, "this lifetime..."); - diag.span_label(use_span, "...is used only here"); - if let Some(deletion_span) = deletion_span { - let msg = "elide the single-use lifetime"; + let suggestion = if let Some(deletion_span) = deletion_span { let (use_span, replace_lt) = if elide { let use_span = sess.source_map().span_extend_while_whitespace(use_span); (use_span, String::new()) @@ -226,24 +272,22 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di // issue 107998 for the case such as a wrong function pointer type // `deletion_span` is empty and there is no need to report lifetime uses here - let suggestions = if deletion_span.is_empty() { - vec![(use_span, replace_lt)] - } else { - vec![(deletion_span, String::new()), (use_span, replace_lt)] - }; - diag.multipart_suggestion(msg, suggestions, Applicability::MachineApplicable); - } + let deletion_span = + if deletion_span.is_empty() { None } else { Some(deletion_span) }; + Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt }) + } else { + None + }; + + ctx.emit_span_lint( + lint, + span, + lints::SingleUseLifetime { suggestion, param_span, use_span, ident }, + ); } - BuiltinLintDiag::SingleUseLifetime { param_span: _, use_span: None, deletion_span } => { + BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { debug!(?deletion_span); - if let Some(deletion_span) = deletion_span { - diag.span_suggestion( - deletion_span, - "elide the unused lifetime", - "", - Applicability::MachineApplicable, - ); - } + ctx.emit_span_lint(lint, span, lints::UnusedLifetime { deletion_span, ident }); } BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, @@ -252,19 +296,12 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di named_arg_name, is_formatting_arg, } => { - diag.span_label( - named_arg_sp, - "this named argument is referred to by position in formatting string", - ); - if let Some(positional_arg_for_msg) = position_sp_for_msg { - let msg = format!( - "this formatting argument uses named argument `{named_arg_name}` by position" - ); - diag.span_label(positional_arg_for_msg, msg); - } - - if let Some(positional_arg_to_replace) = position_sp_to_replace { - let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name }; + let (suggestion, name) = if let Some(positional_arg_to_replace) = position_sp_to_replace + { + let mut name = named_arg_name.clone(); + if is_formatting_arg { + name.push('$') + }; let span_to_replace = if let Ok(positional_arg_content) = sess.source_map().span_to_snippet(positional_arg_to_replace) && positional_arg_content.starts_with(':') @@ -273,31 +310,40 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di } else { positional_arg_to_replace }; - diag.span_suggestion_verbose( - span_to_replace, - "use the named argument by name to avoid ambiguity", + (Some(span_to_replace), name) + } else { + (None, String::new()) + }; + + ctx.emit_span_lint( + lint, + span, + lints::NamedArgumentUsedPositionally { + named_arg_sp, + position_label_sp: position_sp_for_msg, + suggestion, name, - Applicability::MaybeIncorrect, - ); - } + named_arg_name, + }, + ) } - BuiltinLintDiag::ByteSliceInPackedStructWithDerive => { - diag.help("consider implementing the trait by hand, or remove the `packed` attribute"); + BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => { + ctx.emit_span_lint(lint, span, lints::ByteSliceInPackedStructWithDerive { ty }) } BuiltinLintDiag::UnusedExternCrate { removal_span } => { - diag.span_suggestion(removal_span, "remove it", "", Applicability::MachineApplicable); + ctx.emit_span_lint(lint, span, lints::UnusedExternCrate { removal_span }) } BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => { let suggestion_span = vis_span.between(ident_span); - diag.span_suggestion_verbose( - suggestion_span, - "convert it to a `use`", - if vis_span.is_empty() { "use " } else { " use " }, - Applicability::MachineApplicable, + let code = if vis_span.is_empty() { "use " } else { " use " }; + ctx.emit_span_lint( + lint, + span, + lints::ExternCrateNotIdiomatic { span: suggestion_span, code }, ); } BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => { - rustc_errors::report_ambiguity_error(diag, ambiguity); + ctx.emit_span_lint(lint, span, lints::AmbiguousGlobImports { ambiguity }); } BuiltinLintDiag::AmbiguousGlobReexports { name, @@ -305,15 +351,15 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di first_reexport_span, duplicate_reexport_span, } => { - diag.span_label( - first_reexport_span, - format!("the name `{name}` in the {namespace} namespace is first re-exported here"), - ); - diag.span_label( - duplicate_reexport_span, - format!( - "but the name `{name}` in the {namespace} namespace is also re-exported here" - ), + ctx.emit_span_lint( + lint, + span, + lints::AmbiguousGlobReexports { + first_reexport: first_reexport_span, + duplicate_reexport: duplicate_reexport_span, + name, + namespace, + }, ); } BuiltinLintDiag::HiddenGlobReexports { @@ -322,38 +368,127 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di glob_reexport_span, private_item_span, } => { - diag.span_note(glob_reexport_span, format!("the name `{name}` in the {namespace} namespace is supposed to be publicly re-exported here")); - diag.span_note(private_item_span, "but the private item here shadows it".to_owned()); - } - BuiltinLintDiag::UnusedQualifications { removal_span } => { - diag.span_suggestion_verbose( - removal_span, - "remove the unnecessary path segments", - "", - Applicability::MachineApplicable, + ctx.emit_span_lint( + lint, + span, + lints::HiddenGlobReexports { + glob_reexport: glob_reexport_span, + private_item: private_item_span, + + name, + namespace, + }, ); } - BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span } => { - diag.span_suggestion_verbose( - if elided { span.shrink_to_hi() } else { span }, - "use the `'static` lifetime", - if elided { "'static " } else { "'static" }, - Applicability::MachineApplicable, - ); + BuiltinLintDiag::UnusedQualifications { removal_span } => { + ctx.emit_span_lint(lint, span, lints::UnusedQualifications { removal_span }); } - BuiltinLintDiag::RedundantImportVisibility { max_vis, span } => { - diag.span_note(span, format!("the most public imported item is `{max_vis}`")); - diag.help( - "reduce the glob import's visibility or increase visibility of imported items", + BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => { + let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; + let code = if elided { "'static " } else { "'static" }; + ctx.emit_span_lint( + lint, + span, + lints::AssociatedConstElidedLifetime { span: lt_span, code, elided }, ); } - BuiltinLintDiag::MaybeTypo { span, name } => { - diag.span_suggestion_verbose( + BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => { + ctx.emit_span_lint( + lint, span, - "an attribute with a similar name exists", - name, - Applicability::MachineApplicable, + lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis }, ); } + BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => { + let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg { + span: typo_span, + typo_name, + }); + ctx.emit_span_lint(lint, span, lints::UnknownDiagnosticAttribute { typo }); + } + BuiltinLintDiag::MacroUseDeprecated => { + ctx.emit_span_lint(lint, span, lints::MacroUseDeprecated) + } + BuiltinLintDiag::UnusedMacroUse => ctx.emit_span_lint(lint, span, lints::UnusedMacroUse), + BuiltinLintDiag::PrivateExternCrateReexport(ident) => { + ctx.emit_span_lint(lint, span, lints::PrivateExternCrateReexport { ident }) + } + BuiltinLintDiag::UnusedLabel => ctx.emit_span_lint(lint, span, lints::UnusedLabel), + BuiltinLintDiag::MacroIsPrivate(ident) => { + ctx.emit_span_lint(lint, span, lints::MacroIsPrivate { ident }) + } + BuiltinLintDiag::UnusedMacroDefinition(name) => { + ctx.emit_span_lint(lint, span, lints::UnusedMacroDefinition { name }) + } + BuiltinLintDiag::MacroRuleNeverUsed(n, name) => { + ctx.emit_span_lint(lint, span, lints::MacroRuleNeverUsed { n: n + 1, name }) + } + BuiltinLintDiag::UnstableFeature(msg) => { + ctx.emit_span_lint(lint, span, lints::UnstableFeature { msg }) + } + BuiltinLintDiag::AvoidUsingIntelSyntax => { + ctx.emit_span_lint(lint, span, lints::AvoidIntelSyntax) + } + BuiltinLintDiag::AvoidUsingAttSyntax => { + ctx.emit_span_lint(lint, span, lints::AvoidAttSyntax) + } + BuiltinLintDiag::IncompleteInclude => { + ctx.emit_span_lint(lint, span, lints::IncompleteInclude) + } + BuiltinLintDiag::UnnameableTestItems => { + ctx.emit_span_lint(lint, span, lints::UnnameableTestItems) + } + BuiltinLintDiag::DuplicateMacroAttribute => { + ctx.emit_span_lint(lint, span, lints::DuplicateMacroAttribute) + } + BuiltinLintDiag::CfgAttrNoAttributes => { + ctx.emit_span_lint(lint, span, lints::CfgAttrNoAttributes) + } + BuiltinLintDiag::CrateTypeInCfgAttr => { + ctx.emit_span_lint(lint, span, lints::CrateTypeInCfgAttr) + } + BuiltinLintDiag::CrateNameInCfgAttr => { + ctx.emit_span_lint(lint, span, lints::CrateNameInCfgAttr) + } + BuiltinLintDiag::MissingFragmentSpecifier => { + ctx.emit_span_lint(lint, span, lints::MissingFragmentSpecifier) + } + BuiltinLintDiag::MetaVariableStillRepeating(name) => { + ctx.emit_span_lint(lint, span, lints::MetaVariableStillRepeating { name }) + } + BuiltinLintDiag::MetaVariableWrongOperator => { + ctx.emit_span_lint(lint, span, lints::MetaVariableWrongOperator) + } + BuiltinLintDiag::DuplicateMatcherBinding => { + ctx.emit_span_lint(lint, span, lints::DuplicateMatcherBinding) + } + BuiltinLintDiag::UnknownMacroVariable(name) => { + ctx.emit_span_lint(lint, span, lints::UnknownMacroVariable { name }) + } + BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => ctx.emit_span_lint( + lint, + span, + lints::UnusedCrateDependency { extern_crate, local_crate }, + ), + BuiltinLintDiag::WasmCAbi => ctx.emit_span_lint(lint, span, lints::WasmCAbi), + BuiltinLintDiag::IllFormedAttributeInput { suggestions } => ctx.emit_span_lint( + lint, + span, + lints::IllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + }, + ), + BuiltinLintDiag::InnerAttributeUnstable { is_macro } => ctx.emit_span_lint( + lint, + span, + if is_macro { + lints::InnerAttributeUnstable::InnerMacroAttribute + } else { + lints::InnerAttributeUnstable::CustomInnerAttribute + }, + ), } } diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs index 3fa04ab75f8..020ca1753cf 100644 --- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs @@ -1,44 +1,27 @@ -use rustc_errors::{Applicability, Diag}; use rustc_middle::bug; use rustc_session::{config::ExpectedValues, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{sym, Span, Symbol}; +use crate::lints; + const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35; -fn check_cfg_expected_note( +fn sort_and_truncate_possibilities( sess: &Session, - possibilities: &[Symbol], - type_: &str, - name: Option<Symbol>, - suffix: &str, -) -> String { - use std::fmt::Write; - + mut possibilities: Vec<Symbol>, +) -> (Vec<Symbol>, usize) { let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected { possibilities.len() } else { std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES) }; - let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>(); - possibilities.sort(); + possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str())); let and_more = possibilities.len().saturating_sub(n_possibilities); - let possibilities = possibilities[..n_possibilities].join("`, `"); - - let mut note = String::with_capacity(50 + possibilities.len()); - - write!(&mut note, "expected {type_}").unwrap(); - if let Some(name) = name { - write!(&mut note, " for `{name}`").unwrap(); - } - write!(&mut note, " are: {suffix}`{possibilities}`").unwrap(); - if and_more > 0 { - write!(&mut note, " and {and_more} more").unwrap(); - } - - note + possibilities.truncate(n_possibilities); + (possibilities, and_more) } enum EscapeQuotes { @@ -61,10 +44,9 @@ fn to_check_cfg_arg(name: Symbol, value: Option<Symbol>, quotes: EscapeQuotes) - pub(super) fn unexpected_cfg_name( sess: &Session, - diag: &mut Diag<'_, ()>, (name, name_span): (Symbol, Span), value: Option<(Symbol, Span)>, -) { +) -> lints::UnexpectedCfgName { #[allow(rustc::potential_query_instability)] let possibilities: Vec<Symbol> = sess.psess.check_config.expecteds.keys().copied().collect(); @@ -87,114 +69,122 @@ pub(super) fn unexpected_cfg_name( let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); let mut is_feature_cfg = name == sym::feature; - if is_feature_cfg && is_from_cargo { - diag.help("consider defining some features in `Cargo.toml`"); + let code_sugg = if is_feature_cfg && is_from_cargo { + lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures // Suggest the most probable if we found one } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { + is_feature_cfg |= best_match == sym::feature; + if let Some(ExpectedValues::Some(best_match_values)) = sess.psess.check_config.expecteds.get(&best_match) { // We will soon sort, so the initial order does not matter. #[allow(rustc::potential_query_instability)] - let mut possibilities = - best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>(); - possibilities.sort(); + let mut possibilities = best_match_values.iter().flatten().collect::<Vec<_>>(); + possibilities.sort_by_key(|s| s.as_str()); + + let get_possibilities_sub = || { + if !possibilities.is_empty() { + let possibilities = + possibilities.iter().copied().cloned().collect::<Vec<_>>().into(); + Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities }) + } else { + None + } + }; - let mut should_print_possibilities = true; if let Some((value, value_span)) = value { if best_match_values.contains(&Some(value)) { - diag.span_suggestion( - name_span, - "there is a config with a similar name and value", - best_match, - Applicability::MaybeIncorrect, - ); - should_print_possibilities = false; + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue { + span: name_span, + code: best_match.to_string(), + } } else if best_match_values.contains(&None) { - diag.span_suggestion( - name_span.to(value_span), - "there is a config with a similar name and no value", - best_match, - Applicability::MaybeIncorrect, - ); - should_print_possibilities = false; + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue { + span: name_span.to(value_span), + code: best_match.to_string(), + } } else if let Some(first_value) = possibilities.first() { - diag.span_suggestion( - name_span.to(value_span), - "there is a config with a similar name and different values", - format!("{best_match} = \"{first_value}\""), - Applicability::MaybeIncorrect, - ); + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { + span: name_span.to(value_span), + code: format!("{best_match} = \"{first_value}\""), + expected: get_possibilities_sub(), + } } else { - diag.span_suggestion( - name_span.to(value_span), - "there is a config with a similar name and different values", - best_match, - Applicability::MaybeIncorrect, - ); - }; + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { + span: name_span.to(value_span), + code: best_match.to_string(), + expected: get_possibilities_sub(), + } + } } else { - diag.span_suggestion( - name_span, - "there is a config with a similar name", - best_match, - Applicability::MaybeIncorrect, - ); - } - - if !possibilities.is_empty() && should_print_possibilities { - let possibilities = possibilities.join("`, `"); - diag.help(format!("expected values for `{best_match}` are: `{possibilities}`")); + lints::unexpected_cfg_name::CodeSuggestion::SimilarName { + span: name_span, + code: best_match.to_string(), + expected: get_possibilities_sub(), + } } } else { - diag.span_suggestion( - name_span, - "there is a config with a similar name", - best_match, - Applicability::MaybeIncorrect, - ); + lints::unexpected_cfg_name::CodeSuggestion::SimilarName { + span: name_span, + code: best_match.to_string(), + expected: None, + } } - - is_feature_cfg |= best_match == sym::feature; } else { - if !names_possibilities.is_empty() && names_possibilities.len() <= 3 { + let similar_values = if !names_possibilities.is_empty() && names_possibilities.len() <= 3 { names_possibilities.sort(); - for cfg_name in names_possibilities.iter() { - diag.span_suggestion( - name_span, - "found config with similar value", - format!("{cfg_name} = \"{name}\""), - Applicability::MaybeIncorrect, - ); - } - } - if !possibilities.is_empty() { - diag.help_once(check_cfg_expected_note(sess, &possibilities, "names", None, "")); + names_possibilities + .iter() + .map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue { + span: name_span, + code: format!("{cfg_name} = \"{name}\""), + }) + .collect() + } else { + vec![] + }; + let expected_names = if !possibilities.is_empty() { + let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities); + Some(lints::unexpected_cfg_name::ExpectedNames { + possibilities: possibilities.into(), + and_more, + }) + } else { + None + }; + lints::unexpected_cfg_name::CodeSuggestion::SimilarValues { + with_similar_values: similar_values, + expected_names, } - } + }; let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes); - if is_from_cargo { - if !is_feature_cfg { - diag.help(format!("consider using a Cargo feature instead")); - diag.help(format!("or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{}'] }}", inst(EscapeQuotes::No))); - diag.help(format!("or consider adding `println!(\"cargo::rustc-check-cfg={}\");` to the top of the `build.rs`", inst(EscapeQuotes::Yes))); - } - diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"); + let invocation_help = if is_from_cargo { + let sub = if !is_feature_cfg { + Some(lints::UnexpectedCfgCargoHelp::new( + &inst(EscapeQuotes::No), + &inst(EscapeQuotes::Yes), + )) + } else { + None + }; + lints::unexpected_cfg_name::InvocationHelp::Cargo { sub } } else { - let inst = inst(EscapeQuotes::No); - diag.help(format!("to expect this configuration use `--check-cfg={inst}`",)); - diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"); - } + lints::unexpected_cfg_name::InvocationHelp::Rustc(lints::UnexpectedCfgRustcHelp::new( + &inst(EscapeQuotes::No), + )) + }; + + lints::UnexpectedCfgName { code_sugg, invocation_help, name } } pub(super) fn unexpected_cfg_value( sess: &Session, - diag: &mut Diag<'_, ()>, (name, name_span): (Symbol, Span), value: Option<(Symbol, Span)>, -) { +) -> lints::UnexpectedCfgValue { let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else { bug!( "it shouldn't be possible to have a diagnostic on a value whose name is not in values" @@ -214,53 +204,53 @@ pub(super) fn unexpected_cfg_value( // Show the full list if all possible values for a given name, but don't do it // for names as the possibilities could be very long - if !possibilities.is_empty() { - diag.note(check_cfg_expected_note( - sess, - &possibilities, - "values", - Some(name), - if have_none_possibility { "(none), " } else { "" }, - )); + let code_sugg = if !possibilities.is_empty() { + let expected_values = { + let (possibilities, and_more) = + sort_and_truncate_possibilities(sess, possibilities.clone()); + lints::unexpected_cfg_value::ExpectedValues { + name, + have_none_possibility, + possibilities: possibilities.into(), + and_more, + } + }; - if let Some((value, value_span)) = value { + let suggestion = if let Some((value, value_span)) = value { // Suggest the most probable if we found one if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) { - diag.span_suggestion( - value_span, - "there is a expected value with a similar name", - format!("\"{best_match}\""), - Applicability::MaybeIncorrect, - ); + Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName { + span: value_span, + best_match, + }) + } else { + None } } else if let &[first_possibility] = &possibilities[..] { - diag.span_suggestion( - name_span.shrink_to_hi(), - "specify a config value", - format!(" = \"{first_possibility}\""), - Applicability::MaybeIncorrect, - ); - } + Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue { + span: name_span.shrink_to_hi(), + first_possibility, + }) + } else { + None + }; + + lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion } } else if have_none_possibility { - diag.note(format!("no expected value for `{name}`")); - if let Some((_value, value_span)) = value { - diag.span_suggestion( - name_span.shrink_to_hi().to(value_span), - "remove the value", - "", - Applicability::MaybeIncorrect, - ); - } + let suggestion = + value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion { + span: name_span.shrink_to_hi().to(value_span), + }); + lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name } } else { - diag.note(format!("no expected values for `{name}`")); - - let sp = if let Some((_value, value_span)) = value { + let span = if let Some((_value, value_span)) = value { name_span.to(value_span) } else { name_span }; - diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect); - } + let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span }; + lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name } + }; // We don't want to suggest adding values to well known names // since those are defined by rustc it-self. Users can still @@ -269,24 +259,35 @@ pub(super) fn unexpected_cfg_value( let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes); - if is_from_cargo { - if name == sym::feature { + let invocation_help = if is_from_cargo { + let help = if name == sym::feature { if let Some((value, _value_span)) = value { - diag.help(format!("consider adding `{value}` as a feature in `Cargo.toml`")); + Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value }) } else { - diag.help("consider defining some features in `Cargo.toml`"); + Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures) } } else if !is_cfg_a_well_know_name { - diag.help(format!("consider using a Cargo feature instead")); - diag.help(format!("or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{}'] }}", inst(EscapeQuotes::No))); - diag.help(format!("or consider adding `println!(\"cargo::rustc-check-cfg={}\");` to the top of the `build.rs`", inst(EscapeQuotes::Yes))); - } - diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"); + Some(lints::unexpected_cfg_value::CargoHelp::Other(lints::UnexpectedCfgCargoHelp::new( + &inst(EscapeQuotes::No), + &inst(EscapeQuotes::Yes), + ))) + } else { + None + }; + lints::unexpected_cfg_value::InvocationHelp::Cargo(help) } else { - if !is_cfg_a_well_know_name { - let inst = inst(EscapeQuotes::No); - diag.help(format!("to expect this configuration use `--check-cfg={inst}`",)); - } - diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"); + let help = if !is_cfg_a_well_know_name { + Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No))) + } else { + None + }; + lints::unexpected_cfg_value::InvocationHelp::Rustc(help) + }; + + lints::UnexpectedCfgValue { + code_sugg, + invocation_help, + has_value: value.is_some(), + value: value.map_or_else(String::new, |(v, _span)| v.to_string()), } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 3f627baf770..736c7a11069 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -14,7 +14,7 @@ //! upon. As the ast is traversed, this keeps track of the current lint level //! for all lint attributes. -use crate::context::{EarlyContext, LintContext, LintStore}; +use crate::context::{EarlyContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use rustc_ast::ptr::P; use rustc_ast::visit::{self as ast_visit, walk_list, Visitor}; @@ -44,14 +44,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { #[allow(rustc::diagnostic_outside_of_impl)] fn inlined_check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { - let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint; - self.context.span_lint_with_diagnostics( - lint_id.lint, - Some(span), - msg, - |_| {}, - diagnostic, - ); + let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; + self.context.span_lint_with_diagnostics(lint_id.lint, span, diagnostic); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index bc0c8cf85d8..3bd6faca379 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -5,16 +5,22 @@ use std::num::NonZero; use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, - LintDiagnostic, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, + codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, + ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp, + Subdiagnostic, SuggestionStyle, }; -use rustc_hir::def_id::DefId; +use rustc_hir::{def::Namespace, def_id::DefId}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{ inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt, }; -use rustc_session::Session; -use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol}; +use rustc_session::{lint::AmbiguityErrorDiag, Session}; +use rustc_span::{ + edition::Edition, + sym, + symbol::{Ident, MacroRulesNormalizedIdent}, + Span, Symbol, +}; use crate::{ builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext, @@ -1947,3 +1953,837 @@ pub struct UnitBindingsDiag { #[label] pub label: Span, } + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_asm_labels)] +#[help] +#[note] +pub struct BuiltinNamedAsmLabel; + +#[derive(Subdiagnostic)] +#[help(lint_unexpected_cfg_add_cargo_feature)] +#[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)] +#[help(lint_unexpected_cfg_add_build_rs_println)] +pub struct UnexpectedCfgCargoHelp { + pub build_rs_println: String, + pub cargo_toml_lint_cfg: String, +} + +impl UnexpectedCfgCargoHelp { + pub fn new(unescaped: &str, escaped: &str) -> Self { + Self { + cargo_toml_lint_cfg: format!( + "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}", + ), + build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");",), + } + } +} + +#[derive(Subdiagnostic)] +#[help(lint_unexpected_cfg_add_cmdline_arg)] +pub struct UnexpectedCfgRustcHelp { + pub cmdline_arg: String, +} + +impl UnexpectedCfgRustcHelp { + pub fn new(unescaped: &str) -> Self { + Self { cmdline_arg: format!("--check-cfg={unescaped}") } + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_unexpected_cfg_name)] +pub struct UnexpectedCfgName { + #[subdiagnostic] + pub code_sugg: unexpected_cfg_name::CodeSuggestion, + #[subdiagnostic] + pub invocation_help: unexpected_cfg_name::InvocationHelp, + + pub name: Symbol, +} + +pub mod unexpected_cfg_name { + use rustc_errors::DiagSymbolList; + use rustc_macros::Subdiagnostic; + use rustc_span::{Span, Symbol}; + + #[derive(Subdiagnostic)] + pub enum CodeSuggestion { + #[help(lint_unexpected_cfg_define_features)] + DefineFeatures, + #[suggestion( + lint_unexpected_cfg_name_similar_name_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameAndValue { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + lint_unexpected_cfg_name_similar_name_no_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameNoValue { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + lint_unexpected_cfg_name_similar_name_different_values, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameDifferentValues { + #[primary_span] + span: Span, + code: String, + #[subdiagnostic] + expected: Option<ExpectedValues>, + }, + #[suggestion( + lint_unexpected_cfg_name_similar_name, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarName { + #[primary_span] + span: Span, + code: String, + #[subdiagnostic] + expected: Option<ExpectedValues>, + }, + SimilarValues { + #[subdiagnostic] + with_similar_values: Vec<FoundWithSimilarValue>, + #[subdiagnostic] + expected_names: Option<ExpectedNames>, + }, + } + + #[derive(Subdiagnostic)] + #[help(lint_unexpected_cfg_name_expected_values)] + pub struct ExpectedValues { + pub best_match: Symbol, + pub possibilities: DiagSymbolList, + } + + #[derive(Subdiagnostic)] + #[suggestion( + lint_unexpected_cfg_name_with_similar_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + pub struct FoundWithSimilarValue { + #[primary_span] + pub span: Span, + pub code: String, + } + + #[derive(Subdiagnostic)] + #[help_once(lint_unexpected_cfg_name_expected_names)] + pub struct ExpectedNames { + pub possibilities: DiagSymbolList, + pub and_more: usize, + } + + #[derive(Subdiagnostic)] + pub enum InvocationHelp { + #[note(lint_unexpected_cfg_doc_cargo)] + Cargo { + #[subdiagnostic] + sub: Option<super::UnexpectedCfgCargoHelp>, + }, + #[note(lint_unexpected_cfg_doc_rustc)] + Rustc(#[subdiagnostic] super::UnexpectedCfgRustcHelp), + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_unexpected_cfg_value)] +pub struct UnexpectedCfgValue { + #[subdiagnostic] + pub code_sugg: unexpected_cfg_value::CodeSuggestion, + #[subdiagnostic] + pub invocation_help: unexpected_cfg_value::InvocationHelp, + + pub has_value: bool, + pub value: String, +} + +pub mod unexpected_cfg_value { + use rustc_errors::DiagSymbolList; + use rustc_macros::Subdiagnostic; + use rustc_span::{Span, Symbol}; + + #[derive(Subdiagnostic)] + pub enum CodeSuggestion { + ChangeValue { + #[subdiagnostic] + expected_values: ExpectedValues, + #[subdiagnostic] + suggestion: Option<ChangeValueSuggestion>, + }, + #[note(lint_unexpected_cfg_value_no_expected_value)] + RemoveValue { + #[subdiagnostic] + suggestion: Option<RemoveValueSuggestion>, + + name: Symbol, + }, + #[note(lint_unexpected_cfg_value_no_expected_values)] + RemoveCondition { + #[subdiagnostic] + suggestion: RemoveConditionSuggestion, + + name: Symbol, + }, + } + + #[derive(Subdiagnostic)] + pub enum ChangeValueSuggestion { + #[suggestion( + lint_unexpected_cfg_value_similar_name, + code = r#""{best_match}""#, + applicability = "maybe-incorrect" + )] + SimilarName { + #[primary_span] + span: Span, + best_match: Symbol, + }, + #[suggestion( + lint_unexpected_cfg_value_specify_value, + code = r#" = "{first_possibility}""#, + applicability = "maybe-incorrect" + )] + SpecifyValue { + #[primary_span] + span: Span, + first_possibility: Symbol, + }, + } + + #[derive(Subdiagnostic)] + #[suggestion( + lint_unexpected_cfg_value_remove_value, + code = "", + applicability = "maybe-incorrect" + )] + pub struct RemoveValueSuggestion { + #[primary_span] + pub span: Span, + } + + #[derive(Subdiagnostic)] + #[suggestion( + lint_unexpected_cfg_value_remove_condition, + code = "", + applicability = "maybe-incorrect" + )] + pub struct RemoveConditionSuggestion { + #[primary_span] + pub span: Span, + } + + #[derive(Subdiagnostic)] + #[note(lint_unexpected_cfg_value_expected_values)] + pub struct ExpectedValues { + pub name: Symbol, + pub have_none_possibility: bool, + pub possibilities: DiagSymbolList, + pub and_more: usize, + } + + #[derive(Subdiagnostic)] + pub enum InvocationHelp { + #[note(lint_unexpected_cfg_doc_cargo)] + Cargo(#[subdiagnostic] Option<CargoHelp>), + #[note(lint_unexpected_cfg_doc_rustc)] + Rustc(#[subdiagnostic] Option<super::UnexpectedCfgRustcHelp>), + } + + #[derive(Subdiagnostic)] + pub enum CargoHelp { + #[help(lint_unexpected_cfg_value_add_feature)] + AddFeature { + value: Symbol, + }, + #[help(lint_unexpected_cfg_define_features)] + DefineFeatures, + Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp), + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_macro_use_deprecated)] +pub struct MacroUseDeprecated; + +#[derive(LintDiagnostic)] +#[diag(lint_unused_macro_use)] +pub struct UnusedMacroUse; + +#[derive(LintDiagnostic)] +#[diag(lint_private_extern_crate_reexport)] +pub struct PrivateExternCrateReexport { + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_label)] +pub struct UnusedLabel; + +#[derive(LintDiagnostic)] +#[diag(lint_macro_is_private)] +pub struct MacroIsPrivate { + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_macro_definition)] +pub struct UnusedMacroDefinition { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_macro_rule_never_used)] +pub struct MacroRuleNeverUsed { + pub n: usize, + pub name: Symbol, +} + +pub struct UnstableFeature { + pub msg: DiagMessage, +} + +impl<'a> LintDiagnostic<'a, ()> for UnstableFeature { + fn decorate_lint<'b>(self, _diag: &'b mut Diag<'a, ()>) {} + + fn msg(&self) -> DiagMessage { + self.msg.clone() + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_avoid_intel_syntax)] +pub struct AvoidIntelSyntax; + +#[derive(LintDiagnostic)] +#[diag(lint_avoid_att_syntax)] +pub struct AvoidAttSyntax; + +#[derive(LintDiagnostic)] +#[diag(lint_incomplete_include)] +pub struct IncompleteInclude; + +#[derive(LintDiagnostic)] +#[diag(lint_unnameable_test_items)] +pub struct UnnameableTestItems; + +#[derive(LintDiagnostic)] +#[diag(lint_duplicate_macro_attribute)] +pub struct DuplicateMacroAttribute; + +#[derive(LintDiagnostic)] +#[diag(lint_cfg_attr_no_attributes)] +pub struct CfgAttrNoAttributes; + +#[derive(LintDiagnostic)] +#[diag(lint_crate_type_in_cfg_attr_deprecated)] +pub struct CrateTypeInCfgAttr; + +#[derive(LintDiagnostic)] +#[diag(lint_crate_name_in_cfg_attr_deprecated)] +pub struct CrateNameInCfgAttr; + +#[derive(LintDiagnostic)] +#[diag(lint_missing_fragment_specifier)] +pub struct MissingFragmentSpecifier; + +#[derive(LintDiagnostic)] +#[diag(lint_metavariable_still_repeating)] +pub struct MetaVariableStillRepeating { + pub name: MacroRulesNormalizedIdent, +} + +#[derive(LintDiagnostic)] +#[diag(lint_metavariable_wrong_operator)] +pub struct MetaVariableWrongOperator; + +#[derive(LintDiagnostic)] +#[diag(lint_duplicate_matcher_binding)] +pub struct DuplicateMatcherBinding; + +#[derive(LintDiagnostic)] +#[diag(lint_unknown_macro_variable)] +pub struct UnknownMacroVariable { + pub name: MacroRulesNormalizedIdent, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_crate_dependency)] +pub struct UnusedCrateDependency { + pub extern_crate: Symbol, + pub local_crate: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_wasm_c_abi)] +pub struct WasmCAbi; + +#[derive(LintDiagnostic)] +#[diag(lint_ill_formed_attribute_input)] +pub struct IllFormedAttributeInput { + pub num_suggestions: usize, + pub suggestions: DiagArgValue, +} + +#[derive(LintDiagnostic)] +pub enum InnerAttributeUnstable { + #[diag(lint_inner_macro_attribute_unstable)] + InnerMacroAttribute, + #[diag(lint_custom_inner_attribute_unstable)] + CustomInnerAttribute, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unknown_diagnostic_attribute)] +pub struct UnknownDiagnosticAttribute { + #[subdiagnostic] + pub typo: Option<UnknownDiagnosticAttributeTypoSugg>, +} + +#[derive(Subdiagnostic)] +#[suggestion( + lint_unknown_diagnostic_attribute_typo_sugg, + style = "verbose", + code = "{typo_name}", + applicability = "machine-applicable" +)] +pub struct UnknownDiagnosticAttributeTypoSugg { + #[primary_span] + pub span: Span, + pub typo_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unicode_text_flow)] +#[note] +pub struct UnicodeTextFlow { + #[label] + pub comment_span: Span, + #[subdiagnostic] + pub characters: Vec<UnicodeCharNoteSub>, + #[subdiagnostic] + pub suggestions: Option<UnicodeTextFlowSuggestion>, + + pub num_codepoints: usize, +} + +#[derive(Subdiagnostic)] +#[label(lint_label_comment_char)] +pub struct UnicodeCharNoteSub { + #[primary_span] + pub span: Span, + pub c_debug: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable", style = "hidden")] +pub struct UnicodeTextFlowSuggestion { + #[suggestion_part(code = "")] + pub spans: Vec<Span>, +} + +#[derive(LintDiagnostic)] +#[diag(lint_abs_path_with_module)] +pub struct AbsPathWithModule { + #[subdiagnostic] + pub sugg: AbsPathWithModuleSugg, +} + +#[derive(Subdiagnostic)] +#[suggestion(lint_suggestion, code = "{replacement}")] +pub struct AbsPathWithModuleSugg { + #[primary_span] + pub span: Span, + #[applicability] + pub applicability: Applicability, + pub replacement: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_proc_macro_derive_resolution_fallback)] +pub struct ProcMacroDeriveResolutionFallback { + #[label] + pub span: Span, + pub ns: Namespace, + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(lint_macro_expanded_macro_exports_accessed_by_absolute_paths)] +pub struct MacroExpandedMacroExportsAccessedByAbsolutePaths { + #[note] + pub definition: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_hidden_lifetime_parameters)] +pub struct ElidedLifetimesInPaths { + #[subdiagnostic] + pub subdiag: ElidedLifetimeInPathSubdiag, +} + +#[derive(LintDiagnostic)] +#[diag(lint_invalid_crate_type_value)] +pub struct UnknownCrateTypes { + #[subdiagnostic] + pub sugg: Option<UnknownCrateTypesSub>, +} + +#[derive(Subdiagnostic)] +#[suggestion(lint_suggestion, code = r#""{candidate}""#, applicability = "maybe-incorrect")] +pub struct UnknownCrateTypesSub { + #[primary_span] + pub span: Span, + pub candidate: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_imports)] +pub struct UnusedImports { + #[subdiagnostic] + pub sugg: UnusedImportsSugg, + #[help] + pub test_module_span: Option<Span>, + + pub span_snippets: DiagArgValue, + pub num_snippets: usize, +} + +#[derive(Subdiagnostic)] +pub enum UnusedImportsSugg { + #[suggestion( + lint_suggestion_remove_whole_use, + applicability = "machine-applicable", + code = "", + style = "tool-only" + )] + RemoveWholeUse { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + lint_suggestion_remove_imports, + applicability = "machine-applicable", + style = "tool-only" + )] + RemoveImports { + #[suggestion_part(code = "")] + remove_spans: Vec<Span>, + num_to_remove: usize, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_redundant_import)] +pub struct RedundantImport { + #[subdiagnostic] + pub subs: Vec<RedundantImportSub>, + + pub ident: Ident, +} + +#[derive(Subdiagnostic)] +pub enum RedundantImportSub { + #[label(lint_label_imported_here)] + ImportedHere(#[primary_span] Span), + #[label(lint_label_defined_here)] + DefinedHere(#[primary_span] Span), + #[label(lint_label_imported_prelude)] + ImportedPrelude(#[primary_span] Span), + #[label(lint_label_defined_prelude)] + DefinedPrelude(#[primary_span] Span), +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_doc_comment)] +#[help] +pub struct UnusedDocComment { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +pub enum PatternsInFnsWithoutBody { + #[diag(lint_pattern_in_foreign)] + Foreign { + #[subdiagnostic] + sub: PatternsInFnsWithoutBodySub, + }, + #[diag(lint_pattern_in_bodiless)] + Bodiless { + #[subdiagnostic] + sub: PatternsInFnsWithoutBodySub, + }, +} + +#[derive(Subdiagnostic)] +#[suggestion(lint_remove_mut_from_pattern, code = "{ident}", applicability = "machine-applicable")] +pub struct PatternsInFnsWithoutBodySub { + #[primary_span] + pub span: Span, + + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(lint_extern_without_abi)] +#[help] +pub struct MissingAbi { + #[label] + pub span: Span, + + pub default_abi: &'static str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_legacy_derive_helpers)] +pub struct LegacyDeriveHelpers { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_proc_macro_back_compat)] +#[note] +pub struct ProcMacroBackCompat { + pub crate_name: String, + pub fixed_version: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_or_patterns_back_compat)] +pub struct OrPatternsBackCompat { + #[suggestion(code = "{suggestion}", applicability = "machine-applicable")] + pub span: Span, + pub suggestion: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_reserved_prefix)] +pub struct ReservedPrefix { + #[label] + pub label: Span, + #[suggestion(code = " ", applicability = "machine-applicable")] + pub suggestion: Span, + + pub prefix: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_builtin_attribute)] +pub struct UnusedBuiltinAttribute { + #[note] + pub invoc_span: Span, + + pub attr_name: Symbol, + pub macro_name: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_trailing_semi_macro)] +pub struct TrailingMacro { + #[note(lint_note1)] + #[note(lint_note2)] + pub is_trailing: bool, + + pub name: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(lint_break_with_label_and_loop)] +pub struct BreakWithLabelAndLoop { + #[subdiagnostic] + pub sub: BreakWithLabelAndLoopSub, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")] +pub struct BreakWithLabelAndLoopSub { + #[suggestion_part(code = "(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_deprecated_where_clause_location)] +#[note] +pub struct DeprecatedWhereClauseLocation { + #[subdiagnostic] + pub suggestion: DeprecatedWhereClauseLocationSugg, +} + +#[derive(Subdiagnostic)] +pub enum DeprecatedWhereClauseLocationSugg { + #[multipart_suggestion(lint_suggestion_move_to_end, applicability = "machine-applicable")] + MoveToEnd { + #[suggestion_part(code = "")] + left: Span, + #[suggestion_part(code = "{sugg}")] + right: Span, + + sugg: String, + }, + #[suggestion(lint_suggestion_remove_where, code = "", applicability = "machine-applicable")] + RemoveWhere { + #[primary_span] + span: Span, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_single_use_lifetime)] +pub struct SingleUseLifetime { + #[label(lint_label_param)] + pub param_span: Span, + #[label(lint_label_use)] + pub use_span: Span, + #[subdiagnostic] + pub suggestion: Option<SingleUseLifetimeSugg>, + + pub ident: Ident, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")] +pub struct SingleUseLifetimeSugg { + #[suggestion_part(code = "")] + pub deletion_span: Option<Span>, + #[suggestion_part(code = "{replace_lt}")] + pub use_span: Span, + + pub replace_lt: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_lifetime)] +pub struct UnusedLifetime { + #[suggestion(code = "", applicability = "machine-applicable")] + pub deletion_span: Option<Span>, + + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(lint_named_argument_used_positionally)] +pub struct NamedArgumentUsedPositionally { + #[label(lint_label_named_arg)] + pub named_arg_sp: Span, + #[label(lint_label_position_arg)] + pub position_label_sp: Option<Span>, + #[suggestion(style = "verbose", code = "{name}", applicability = "maybe-incorrect")] + pub suggestion: Option<Span>, + + pub name: String, + pub named_arg_name: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_byte_slice_in_packed_struct_with_derive)] +#[help] +pub struct ByteSliceInPackedStructWithDerive { + // FIXME: make this translatable + pub ty: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_extern_crate)] +pub struct UnusedExternCrate { + #[suggestion(code = "", applicability = "machine-applicable")] + pub removal_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_extern_crate_not_idiomatic)] +pub struct ExternCrateNotIdiomatic { + #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")] + pub span: Span, + + pub code: &'static str, +} + +// FIXME: make this translatable +pub struct AmbiguousGlobImports { + pub ambiguity: AmbiguityErrorDiag, +} + +impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { + rustc_errors::report_ambiguity_error(diag, self.ambiguity); + } + + fn msg(&self) -> DiagMessage { + DiagMessage::Str(self.ambiguity.msg.clone().into()) + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_ambiguous_glob_reexport)] +pub struct AmbiguousGlobReexports { + #[label(lint_label_first_reexport)] + pub first_reexport: Span, + #[label(lint_label_duplicate_reexport)] + pub duplicate_reexport: Span, + + pub name: String, + // FIXME: make this translatable + pub namespace: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_hidden_glob_reexport)] +pub struct HiddenGlobReexports { + #[note(lint_note_glob_reexport)] + pub glob_reexport: Span, + #[note(lint_note_private_item)] + pub private_item: Span, + + pub name: String, + // FIXME: make this translatable + pub namespace: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unnecessary_qualification)] +pub struct UnusedQualifications { + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub removal_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_associated_const_elided_lifetime)] +pub struct AssociatedConstElidedLifetime { + #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")] + pub span: Span, + + pub code: &'static str, + pub elided: bool, +} + +#[derive(LintDiagnostic)] +#[diag(lint_redundant_import_visibility)] +pub struct RedundantImportVisibility { + #[note] + pub span: Span, + #[help] + pub help: (), + + pub import_vis: String, + pub max_vis: String, +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index e06e3e9b805..1941b0b1264 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -6,10 +6,12 @@ use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; use rustc_error_messages::{DiagMessage, MultiSpan}; +use rustc_hir::def::Namespace; use rustc_hir::HashStableContext; use rustc_hir::HirId; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; +use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::{sym, symbol::Ident, Span, Symbol}; use rustc_target::spec::abi::Abi; @@ -565,19 +567,44 @@ pub struct AmbiguityErrorDiag { pub b2_help_msgs: Vec<String>, } +#[derive(Debug, Clone)] +pub enum DeprecatedSinceKind { + InEffect, + InFuture, + InVersion(String), +} + // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). #[derive(Debug)] pub enum BuiltinLintDiag { - Normal, AbsPathWithModule(Span), - ProcMacroDeriveResolutionFallback(Span), + ProcMacroDeriveResolutionFallback { + span: Span, + ns: Namespace, + ident: Ident, + }, MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), ElidedLifetimesInPaths(usize, Span, bool, Span), - UnknownCrateTypes(Span, String, String), - UnusedImports(String, Vec<(Span, String)>, Option<Span>), + UnknownCrateTypes { + span: Span, + candidate: Option<Symbol>, + }, + UnusedImports { + remove_whole_use: bool, + num_to_remove: usize, + remove_spans: Vec<Span>, + test_module_span: Option<Span>, + span_snippets: Vec<String>, + }, RedundantImport(Vec<(Span, bool)>, Ident), - DeprecatedMacro(Option<Symbol>, Span), + DeprecatedMacro { + suggestion: Option<Symbol>, + suggestion_span: Span, + note: Option<Symbol>, + path: String, + since_kind: DeprecatedSinceKind, + }, MissingAbi(Span, Abi), UnusedDocComment(Span), UnusedBuiltinAttribute { @@ -585,18 +612,24 @@ pub enum BuiltinLintDiag { macro_name: String, invoc_span: Span, }, - PatternsInFnsWithoutBody(Span, Ident), + PatternsInFnsWithoutBody { + span: Span, + ident: Ident, + is_foreign: bool, + }, LegacyDeriveHelpers(Span), - ProcMacroBackCompat(String), + ProcMacroBackCompat { + crate_name: String, + fixed_version: String, + }, OrPatternsBackCompat(Span, String), - ReservedPrefix(Span), + ReservedPrefix(Span, String), TrailingMacro(bool, Ident), BreakWithLabelAndLoop(Span), - NamedAsmLabel(String), UnicodeTextFlow(Span, String), UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), - DeprecatedWhereclauseLocation(Option<(Span, String)>), + DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, @@ -606,6 +639,7 @@ pub enum BuiltinLintDiag { /// Span of the single use, or None if the lifetime is never used. /// If true, the lifetime will be fully elided. use_span: Option<(Span, bool)>, + ident: Ident, }, NamedArgumentUsedPositionally { /// Span where the named argument is used by position and will be replaced with the named @@ -620,7 +654,10 @@ pub enum BuiltinLintDiag { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, - ByteSliceInPackedStructWithDerive, + ByteSliceInPackedStructWithDerive { + // FIXME: enum of byte/string + ty: String, + }, UnusedExternCrate { removal_span: Span, }, @@ -662,10 +699,43 @@ pub enum BuiltinLintDiag { RedundantImportVisibility { span: Span, max_vis: String, + import_vis: String, }, - MaybeTypo { + UnknownDiagnosticAttribute { span: Span, - name: Symbol, + typo_name: Option<Symbol>, + }, + MacroUseDeprecated, + UnusedMacroUse, + PrivateExternCrateReexport(Ident), + UnusedLabel, + MacroIsPrivate(Ident), + UnusedMacroDefinition(Symbol), + MacroRuleNeverUsed(usize, Symbol), + UnstableFeature(DiagMessage), + AvoidUsingIntelSyntax, + AvoidUsingAttSyntax, + IncompleteInclude, + UnnameableTestItems, + DuplicateMacroAttribute, + CfgAttrNoAttributes, + CrateTypeInCfgAttr, + CrateNameInCfgAttr, + MissingFragmentSpecifier, + MetaVariableStillRepeating(MacroRulesNormalizedIdent), + MetaVariableWrongOperator, + DuplicateMatcherBinding, + UnknownMacroVariable(MacroRulesNormalizedIdent), + UnusedCrateDependency { + extern_crate: Symbol, + local_crate: Symbol, + }, + WasmCAbi, + IllFormedAttributeInput { + suggestions: Vec<String>, + }, + InnerAttributeUnstable { + is_macro: bool, }, } @@ -676,9 +746,6 @@ pub struct BufferedEarlyLint { /// The span of code that we are linting on. pub span: MultiSpan, - /// The lint message. - pub msg: DiagMessage, - /// The `NodeId` of the AST node that generated the lint. pub node_id: NodeId, @@ -706,12 +773,10 @@ impl LintBuffer { lint: &'static Lint, node_id: NodeId, span: MultiSpan, - msg: impl Into<DiagMessage>, diagnostic: BuiltinLintDiag, ) { let lint_id = LintId::of(lint); - let msg = msg.into(); - self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic }); + self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, diagnostic }); } pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> { @@ -724,20 +789,9 @@ impl LintBuffer { lint: &'static Lint, id: NodeId, sp: impl Into<MultiSpan>, - msg: impl Into<DiagMessage>, - ) { - self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiag::Normal) - } - - pub fn buffer_lint_with_diagnostic( - &mut self, - lint: &'static Lint, - id: NodeId, - sp: impl Into<MultiSpan>, - msg: impl Into<DiagMessage>, diagnostic: BuiltinLintDiag, ) { - self.add_lint(lint, id, sp.into(), msg, diagnostic) + self.add_lint(lint, id, sp.into(), diagnostic) } } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index ae481efb263..38d4a5ee61c 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -158,7 +158,9 @@ impl DiagnosticDeriveVariantBuilder { let slug = subdiag.slug.unwrap_or_else(|| match subdiag.kind { SubdiagnosticKind::Label => parse_quote! { _subdiag::label }, SubdiagnosticKind::Note => parse_quote! { _subdiag::note }, + SubdiagnosticKind::NoteOnce => parse_quote! { _subdiag::note_once }, SubdiagnosticKind::Help => parse_quote! { _subdiag::help }, + SubdiagnosticKind::HelpOnce => parse_quote! { _subdiag::help_once }, SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn }, SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion }, SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), @@ -233,9 +235,11 @@ impl DiagnosticDeriveVariantBuilder { }; let fn_ident = format_ident!("{}", subdiag); match subdiag { - SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { - Ok(self.add_subdiagnostic(&fn_ident, slug)) - } + SubdiagnosticKind::Note + | SubdiagnosticKind::NoteOnce + | SubdiagnosticKind::Help + | SubdiagnosticKind::HelpOnce + | SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, slug)), SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => { throw_invalid_attr!(attr, |diag| diag .help("`#[label]` and `#[suggestion]` can only be applied to fields")); @@ -347,7 +351,11 @@ impl DiagnosticDeriveVariantBuilder { report_error_if_not_applied_to_span(attr, &info)?; Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } - SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { + SubdiagnosticKind::Note + | SubdiagnosticKind::NoteOnce + | SubdiagnosticKind::Help + | SubdiagnosticKind::HelpOnce + | SubdiagnosticKind::Warn => { let inner = info.ty.inner_type(); if type_matches_path(inner, &["rustc_span", "Span"]) || type_matches_path(inner, &["rustc_span", "MultiSpan"]) diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 45236771bce..69014f39925 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -510,11 +510,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { .map(|binding| self.generate_field_attr_code(binding, kind_stats)) .collect(); - if kind_slugs.is_empty() { + if kind_slugs.is_empty() && !self.has_subdiagnostic { if self.is_enum { // It's okay for a variant to not be a subdiagnostic at all.. return Ok(quote! {}); - } else if !self.has_subdiagnostic { + } else { // ..but structs should always be _something_. throw_span_err!( self.variant.ast().ident.span().unwrap(), diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 4684306e235..05a5a32514b 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -575,8 +575,12 @@ pub(super) enum SubdiagnosticKind { Label, /// `#[note(...)]` Note, + /// `#[note_once(...)]` + NoteOnce, /// `#[help(...)]` Help, + /// `#[help_once(...)]` + HelpOnce, /// `#[warning(...)]` Warn, /// `#[suggestion{,_short,_hidden,_verbose}]` @@ -624,7 +628,9 @@ impl SubdiagnosticVariant { let mut kind = match name { "label" => SubdiagnosticKind::Label, "note" => SubdiagnosticKind::Note, + "note_once" => SubdiagnosticKind::NoteOnce, "help" => SubdiagnosticKind::Help, + "help_once" => SubdiagnosticKind::HelpOnce, "warning" => SubdiagnosticKind::Warn, _ => { // Recover old `#[(multipart_)suggestion_*]` syntaxes @@ -682,7 +688,9 @@ impl SubdiagnosticVariant { match kind { SubdiagnosticKind::Label | SubdiagnosticKind::Note + | SubdiagnosticKind::NoteOnce | SubdiagnosticKind::Help + | SubdiagnosticKind::HelpOnce | SubdiagnosticKind::Warn | SubdiagnosticKind::MultipartSuggestion { .. } => { return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false })); @@ -836,7 +844,9 @@ impl SubdiagnosticVariant { } SubdiagnosticKind::Label | SubdiagnosticKind::Note + | SubdiagnosticKind::NoteOnce | SubdiagnosticKind::Help + | SubdiagnosticKind::HelpOnce | SubdiagnosticKind::Warn => {} } @@ -849,7 +859,9 @@ impl quote::IdentFragment for SubdiagnosticKind { match self { SubdiagnosticKind::Label => write!(f, "label"), SubdiagnosticKind::Note => write!(f, "note"), + SubdiagnosticKind::NoteOnce => write!(f, "note_once"), SubdiagnosticKind::Help => write!(f, "help"), + SubdiagnosticKind::HelpOnce => write!(f, "help_once"), SubdiagnosticKind::Warn => write!(f, "warn"), SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"), SubdiagnosticKind::MultipartSuggestion { .. } => { diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index c7b7eadbd9d..de9c916b4f0 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -108,7 +108,9 @@ decl_derive!( // struct attributes diag, help, + help_once, note, + note_once, warning, // field attributes skip_arg, @@ -125,7 +127,9 @@ decl_derive!( // struct attributes diag, help, + help_once, note, + note_once, warning, // field attributes skip_arg, @@ -142,7 +146,9 @@ decl_derive!( // struct/variant attributes label, help, + help_once, note, + note_once, warning, subdiagnostic, suggestion, diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 3d0846ae6de..2f5dfad265c 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -284,8 +284,6 @@ metadata_unsupported_abi = metadata_unsupported_abi_i686 = ABI not supported by `#[link(kind = "raw-dylib")]` on i686 -metadata_wasm_c_abi = - older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88 metadata_wasm_import_form = wasm import module must be of the form `wasm_import_module = "string"` diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e3205fc1d30..be1a73ef0a7 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -20,7 +20,7 @@ use rustc_middle::bug; use rustc_middle::ty::{TyCtxt, TyCtxtFeed}; use rustc_session::config::{self, CrateType, ExternLocation}; use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource}; -use rustc_session::lint; +use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; @@ -975,15 +975,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } self.sess.psess.buffer_lint( - lint::builtin::UNUSED_CRATE_DEPENDENCIES, - span, - ast::CRATE_NODE_ID, - format!( - "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`", - name, - self.tcx.crate_name(LOCAL_CRATE), - name), - ); + lint::builtin::UNUSED_CRATE_DEPENDENCIES, + span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::UnusedCrateDependency { + extern_crate: name_interned, + local_crate: self.tcx.crate_name(LOCAL_CRATE), + }, + ); } } @@ -1020,7 +1019,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { lint::builtin::WASM_C_ABI, span, ast::CRATE_NODE_ID, - crate::fluent_generated::metadata_wasm_c_abi, + BuiltinLintDiag::WasmCAbi, ); } } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 27d555d7e26..f4d619329eb 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -50,6 +50,20 @@ middle_const_not_used_in_type_alias = middle_cycle = a cycle occurred during layout computation +middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note -> + [true] : {$note} + *[other] {""} + } +middle_deprecated_in_future = use of {$kind} `{$path}` that will be deprecated in a future Rust version{$has_note -> + [true] : {$note} + *[other] {""} + } +middle_deprecated_in_version = use of {$kind} `{$path}` that will be deprecated in future version {$version}{$has_note -> + [true] : {$note} + *[other] {""} + } +middle_deprecated_suggestion = replace the use of the deprecated {$kind} + middle_drop_check_overflow = overflow while adding drop-check rules for {$ty} .note = overflowed on {$overflow_ty} diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 67bd53f53da..e5df05763b0 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -9,15 +9,15 @@ use rustc_attr::{ self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Applicability, Diag}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::{self as hir, HirId}; -use rustc_macros::{Decodable, Encodable, HashStable}; +use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; -use rustc_session::lint::{BuiltinLintDiag, Level, Lint, LintBuffer}; +use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer}; use rustc_session::parse::feature_err_issue; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -125,90 +125,107 @@ pub fn report_unstable( } } -pub fn deprecation_suggestion( - diag: &mut Diag<'_, ()>, - kind: &str, - suggestion: Option<Symbol>, - span: Span, -) { - if let Some(suggestion) = suggestion { - diag.span_suggestion_verbose( - span, - format!("replace the use of the deprecated {kind}"), - suggestion, - Applicability::MachineApplicable, - ); - } -} - fn deprecation_lint(is_in_effect: bool) -> &'static Lint { if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE } } -fn deprecation_message( - is_in_effect: bool, - since: DeprecatedSince, - note: Option<Symbol>, - kind: &str, - path: &str, -) -> String { - let message = if is_in_effect { - format!("use of deprecated {kind} `{path}`") +#[derive(Subdiagnostic)] +#[suggestion( + middle_deprecated_suggestion, + code = "{suggestion}", + style = "verbose", + applicability = "machine-applicable" +)] +pub struct DeprecationSuggestion { + #[primary_span] + pub span: Span, + + pub kind: String, + pub suggestion: Symbol, +} + +pub struct Deprecated { + pub sub: Option<DeprecationSuggestion>, + + // FIXME: make this translatable + pub kind: String, + pub path: String, + pub note: Option<Symbol>, + pub since_kind: DeprecatedSinceKind, +} + +impl<'a, G: EmissionGuarantee> rustc_errors::LintDiagnostic<'a, G> for Deprecated { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { + diag.arg("kind", self.kind); + diag.arg("path", self.path); + if let DeprecatedSinceKind::InVersion(version) = self.since_kind { + diag.arg("version", version); + } + if let Some(note) = self.note { + diag.arg("has_note", true); + diag.arg("note", note); + } else { + diag.arg("has_note", false); + } + if let Some(sub) = self.sub { + diag.subdiagnostic(diag.dcx, sub); + } + } + + fn msg(&self) -> rustc_errors::DiagMessage { + match &self.since_kind { + DeprecatedSinceKind::InEffect => crate::fluent_generated::middle_deprecated, + DeprecatedSinceKind::InFuture => crate::fluent_generated::middle_deprecated_in_future, + DeprecatedSinceKind::InVersion(_) => { + crate::fluent_generated::middle_deprecated_in_version + } + } + } +} + +fn deprecated_since_kind(is_in_effect: bool, since: DeprecatedSince) -> DeprecatedSinceKind { + if is_in_effect { + DeprecatedSinceKind::InEffect } else { match since { - DeprecatedSince::RustcVersion(version) => format!( - "use of {kind} `{path}` that will be deprecated in future version {version}" - ), - DeprecatedSince::Future => { - format!("use of {kind} `{path}` that will be deprecated in a future Rust version") + DeprecatedSince::RustcVersion(version) => { + DeprecatedSinceKind::InVersion(version.to_string()) } + DeprecatedSince::Future => DeprecatedSinceKind::InFuture, DeprecatedSince::NonStandard(_) | DeprecatedSince::Unspecified | DeprecatedSince::Err => { unreachable!("this deprecation is always in effect; {since:?}") } } - }; - - match note { - Some(reason) => format!("{message}: {reason}"), - None => message, } } -pub fn deprecation_message_and_lint( - depr: &Deprecation, - kind: &str, - path: &str, -) -> (String, &'static Lint) { - let is_in_effect = depr.is_in_effect(); - ( - deprecation_message(is_in_effect, depr.since, depr.note, kind, path), - deprecation_lint(is_in_effect), - ) -} - -pub fn early_report_deprecation( +pub fn early_report_macro_deprecation( lint_buffer: &mut LintBuffer, - message: String, - suggestion: Option<Symbol>, - lint: &'static Lint, + depr: &Deprecation, span: Span, node_id: NodeId, + path: String, ) { if span.in_derive_expansion() { return; } - let diag = BuiltinLintDiag::DeprecatedMacro(suggestion, span); - lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag); + let is_in_effect = depr.is_in_effect(); + let diag = BuiltinLintDiag::DeprecatedMacro { + suggestion: depr.suggestion, + suggestion_span: span, + note: depr.note, + path, + since_kind: deprecated_since_kind(is_in_effect, depr.since.clone()), + }; + lint_buffer.buffer_lint(deprecation_lint(is_in_effect), node_id, span, diag); } fn late_report_deprecation( tcx: TyCtxt<'_>, - message: String, - suggestion: Option<Symbol>, - lint: &'static Lint, + depr: &Deprecation, span: Span, method_span: Option<Span>, hir_id: HirId, @@ -217,13 +234,26 @@ fn late_report_deprecation( if span.in_derive_expansion() { return; } + + let def_path = with_no_trimmed_paths!(tcx.def_path_str(def_id)); + let def_kind = tcx.def_descr(def_id); + let is_in_effect = depr.is_in_effect(); + let method_span = method_span.unwrap_or(span); - tcx.node_span_lint(lint, hir_id, method_span, message, |diag| { - if let hir::Node::Expr(_) = tcx.hir_node(hir_id) { - let kind = tcx.def_descr(def_id); - deprecation_suggestion(diag, kind, suggestion, method_span); - } - }); + let suggestion = + if let hir::Node::Expr(_) = tcx.hir_node(hir_id) { depr.suggestion } else { None }; + let diag = Deprecated { + sub: suggestion.map(|suggestion| DeprecationSuggestion { + span: method_span, + kind: def_kind.to_owned(), + suggestion, + }), + kind: def_kind.to_owned(), + path: def_path, + note: depr.note, + since_kind: deprecated_since_kind(is_in_effect, depr.since), + }; + tcx.emit_node_span_lint(deprecation_lint(is_in_effect), hir_id, method_span, diag); } /// Result of `TyCtxt::eval_stability`. @@ -352,28 +382,9 @@ impl<'tcx> TyCtxt<'tcx> { // Calculating message for lint involves calling `self.def_path_str`. // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. // So we skip message calculation altogether, if lint is allowed. - let is_in_effect = depr_attr.is_in_effect(); - let lint = deprecation_lint(is_in_effect); + let lint = deprecation_lint(depr_attr.is_in_effect()); if self.lint_level_at_node(lint, id).0 != Level::Allow { - let def_path = with_no_trimmed_paths!(self.def_path_str(def_id)); - let def_kind = self.def_descr(def_id); - - late_report_deprecation( - self, - deprecation_message( - is_in_effect, - depr_attr.since, - depr_attr.note, - def_kind, - &def_path, - ), - depr_attr.suggestion, - lint, - span, - method_span, - id, - def_id, - ); + late_report_deprecation(self, depr_attr, span, method_span, id, def_id); } } }; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d2d200a91af..6eb8bed6a8c 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -370,11 +370,10 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let content = self.str_from(content_start); if contains_text_flow_control_chars(content) { let span = self.mk_sp(start, self.pos); - self.psess.buffer_lint_with_diagnostic( + self.psess.buffer_lint( TEXT_DIRECTION_CODEPOINT_IN_COMMENT, span, ast::CRATE_NODE_ID, - "unicode codepoint changing visible direction of text present in comment", BuiltinLintDiag::UnicodeTextFlow(span, content.to_string()), ); } @@ -723,12 +722,11 @@ impl<'psess, 'src> StringReader<'psess, 'src> { self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg }); } else { // Before Rust 2021, only emit a lint for migration. - self.psess.buffer_lint_with_diagnostic( + self.psess.buffer_lint( RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, prefix_span, ast::CRATE_NODE_ID, - format!("prefix `{prefix}` is unknown"), - BuiltinLintDiag::ReservedPrefix(prefix_span), + BuiltinLintDiag::ReservedPrefix(prefix_span, prefix.to_string()), ); } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d2d21624150..fd3f63a04de 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1913,11 +1913,10 @@ impl<'a> Parser<'a> { | ExprKind::Block(_, None) ) { - self.psess.buffer_lint_with_diagnostic( + self.psess.buffer_lint( BREAK_WITH_LABEL_AND_LOOP, lo.to(expr.span), ast::CRATE_NODE_ID, - "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression", BuiltinLintDiag::BreakWithLabelAndLoop(expr.span), ); } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a46c104b6d9..f43ddadc2ea 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -58,9 +58,15 @@ impl<'a> Parser<'a> { let attrs = self.parse_inner_attributes()?; let post_attr_lo = self.token.span; - let mut items = ThinVec::new(); - while let Some(item) = self.parse_item(ForceCollect::No)? { - self.maybe_consume_incorrect_semicolon(Some(&item)); + let mut items: ThinVec<P<_>> = ThinVec::new(); + + // There shouldn't be any stray semicolons before or after items. + // `parse_item` consumes the appropriate semicolons so any leftover is an error. + loop { + while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons + let Some(item) = self.parse_item(ForceCollect::No)? else { + break; + }; items.push(item); } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index f88edf29dce..b91ef1ae1f3 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -10,6 +10,7 @@ use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::errors::report_lit_error; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, Symbol}; @@ -176,37 +177,26 @@ fn emit_malformed_attribute( }; let error_msg = format!("malformed `{name}` attribute input"); - let mut msg = "attribute must be of the form ".to_owned(); let mut suggestions = vec![]; - let mut first = true; let inner = if style == ast::AttrStyle::Inner { "!" } else { "" }; if template.word { - first = false; - let code = format!("#{inner}[{name}]"); - msg.push_str(&format!("`{code}`")); - suggestions.push(code); + suggestions.push(format!("#{inner}[{name}]")); } if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#{inner}[{name}({descr})]"); - msg.push_str(&format!("`{code}`")); - suggestions.push(code); + suggestions.push(format!("#{inner}[{name}({descr})]")); } if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#{inner}[{name} = \"{descr}\"]"); - msg.push_str(&format!("`{code}`")); - suggestions.push(code); + suggestions.push(format!("#{inner}[{name} = \"{descr}\"]")); } - suggestions.sort(); if should_warn(name) { - psess.buffer_lint(ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg); + psess.buffer_lint( + ILL_FORMED_ATTRIBUTE_INPUT, + span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::IllFormedAttributeInput { suggestions: suggestions.clone() }, + ); } else { + suggestions.sort(); psess .dcx .struct_span_err(span, error_msg) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 180e7f6def3..fc3669fecc2 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -32,7 +32,7 @@ use rustc_ast as ast; use rustc_ast::visit::{self, Visitor}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{pluralize, MultiSpan}; +use rustc_errors::MultiSpan; use rustc_hir::def::{DefKind, Res}; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES}; use rustc_session::lint::builtin::{UNUSED_IMPORTS, UNUSED_QUALIFICATIONS}; @@ -151,11 +151,10 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { // We do this in any edition. if warn_if_unused { if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) { - self.r.lint_buffer.buffer_lint_with_diagnostic( + self.r.lint_buffer.buffer_lint( UNUSED_EXTERN_CRATES, extern_crate.id, span, - "unused extern crate", BuiltinLintDiag::UnusedExternCrate { removal_span: extern_crate.span_with_attributes, }, @@ -204,11 +203,10 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { .span .find_ancestor_inside(extern_crate.span) .unwrap_or(extern_crate.ident.span); - self.r.lint_buffer.buffer_lint_with_diagnostic( + self.r.lint_buffer.buffer_lint( UNUSED_EXTERN_CRATES, extern_crate.id, extern_crate.span, - "`extern crate` is not idiomatic in the new edition", BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span }, ); } @@ -394,10 +392,7 @@ impl Resolver<'_, '_> { MACRO_USE_EXTERN_CRATE, import.root_id, import.span, - "deprecated `#[macro_use]` attribute used to \ - import macros should be replaced at use sites \ - with a `use` item to import the macro \ - instead", + BuiltinLintDiag::MacroUseDeprecated, ); } } @@ -414,8 +409,12 @@ impl Resolver<'_, '_> { } } ImportKind::MacroUse { .. } => { - let msg = "unused `#[macro_use]` import"; - self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg); + self.lint_buffer.buffer_lint( + UNUSED_IMPORTS, + import.root_id, + import.span, + BuiltinLintDiag::UnusedMacroUse, + ); } _ => {} } @@ -434,20 +433,12 @@ impl Resolver<'_, '_> { visitor.report_unused_extern_crate_items(maybe_unused_extern_crates); for unused in visitor.unused_imports.values() { - let mut fixes = Vec::new(); - let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) { - UnusedSpanResult::Used => continue, - UnusedSpanResult::Unused { spans, remove } => { - fixes.push((remove, String::new())); - spans - } - UnusedSpanResult::PartialUnused { spans, remove } => { - for fix in &remove { - fixes.push((*fix, String::new())); - } - spans - } - }; + let (spans, remove_spans) = + match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) { + UnusedSpanResult::Used => continue, + UnusedSpanResult::Unused { spans, remove } => (spans, vec![remove]), + UnusedSpanResult::PartialUnused { spans, remove } => (spans, remove), + }; let ms = MultiSpan::from_spans(spans); @@ -459,23 +450,8 @@ impl Resolver<'_, '_> { .collect::<Vec<String>>(); span_snippets.sort(); - let msg = format!( - "unused import{}{}", - pluralize!(ms.primary_spans().len()), - if !span_snippets.is_empty() { - format!(": {}", span_snippets.join(", ")) - } else { - String::new() - } - ); - - let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span { - "remove the whole `use` item" - } else if ms.primary_spans().len() > 1 { - "remove the unused imports" - } else { - "remove the unused import" - }; + let remove_whole_use = remove_spans.len() == 1 && remove_spans[0] == unused.item_span; + let num_to_remove = ms.primary_spans().len(); // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]` // attribute; however, if not, suggest adding the attribute. There is no way to @@ -501,12 +477,17 @@ impl Resolver<'_, '_> { } }; - visitor.r.lint_buffer.buffer_lint_with_diagnostic( + visitor.r.lint_buffer.buffer_lint( UNUSED_IMPORTS, unused.use_tree_id, ms, - msg, - BuiltinLintDiag::UnusedImports(fix_msg.into(), fixes, test_module_span), + BuiltinLintDiag::UnusedImports { + remove_whole_use, + num_to_remove, + remove_spans, + test_module_span, + span_snippets, + }, ); } @@ -552,11 +533,10 @@ impl Resolver<'_, '_> { continue; } - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( UNUSED_QUALIFICATIONS, unn_qua.node_id, unn_qua.path_span, - "unnecessary qualification", BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span }, ); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b28312fa473..856cfbc01e8 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -128,13 +128,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.report_with_use_injections(krate); for &(span_use, span_def) in &self.macro_expanded_macro_export_errors { - let msg = "macro-expanded `macro_export` macros from the current crate \ - cannot be referred to by absolute paths"; - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, CRATE_NODE_ID, span_use, - msg, BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def), ); } @@ -145,11 +142,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else { unreachable!() }; - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( AMBIGUOUS_GLOB_IMPORTS, import.root_id, ambiguity_error.ident.span, - diag.msg.to_string(), BuiltinLintDiag::AmbiguousGlobImports { diag }, ); } else { @@ -526,12 +522,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let diag = BuiltinLintDiag::AbsPathWithModule(root_span); - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, node_id, root_span, - "absolute paths must start with `self`, `super`, \ - `crate`, or an external crate name in the 2018 edition", diag, ); } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f88725830f1..57db765c07e 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -524,18 +524,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match binding { Ok(binding) => { if let Some(lint_id) = derive_fallback_lint_id { - this.lint_buffer.buffer_lint_with_diagnostic( + this.lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, orig_ident.span, - format!( - "cannot find {} `{}` in this scope", - ns.descr(), - ident - ), - BuiltinLintDiag::ProcMacroDeriveResolutionFallback( - orig_ident.span, - ), + BuiltinLintDiag::ProcMacroDeriveResolutionFallback { + span: orig_ident.span, + ns, + ident, + }, ); } let misc_flags = if module == this.graph_root { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f53bcb0e9d0..51b87c5a9b0 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -619,11 +619,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && binding.res() != Res::Err && exported_ambiguities.contains(&binding) { - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( AMBIGUOUS_GLOB_REEXPORTS, import.root_id, import.root_span, - "ambiguous glob re-exports", BuiltinLintDiag::AmbiguousGlobReexports { name: key.ident.to_string(), namespace: key.ns.descr().to_string(), @@ -655,11 +654,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && glob_binding.vis.is_public() && !binding.vis.is_public() { - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( HIDDEN_GLOB_REEXPORTS, binding_id, binding.span, - "private item shadows public glob re-export", BuiltinLintDiag::HiddenGlobReexports { name: key.ident.name.to_string(), namespace: key.ns.descr().to_owned(), @@ -1015,17 +1013,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && !max_vis.is_at_least(import_vis, self.tcx) { let def_id = self.local_def_id(id); - let msg = format!( - "glob import doesn't reexport anything with visibility `{}` because no imported item is public enough", - import_vis.to_string(def_id, self.tcx) - ); - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( UNUSED_IMPORTS, id, import.span, - msg, BuiltinLintDiag::RedundantImportVisibility { max_vis: max_vis.to_string(def_id, self.tcx), + import_vis: import_vis.to_string(def_id, self.tcx), span: import.span, }, ); @@ -1252,16 +1246,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !any_successful_reexport { let (ns, binding) = reexport_error.unwrap(); if pub_use_of_private_extern_crate_hack(import, binding) { - let msg = format!( - "extern crate `{ident}` is private, and cannot be \ - re-exported (error E0365), consider declaring with \ - `pub`" - ); self.lint_buffer.buffer_lint( PUB_USE_OF_PRIVATE_EXTERN_CRATE, import_id, import.span, - msg, + BuiltinLintDiag::PrivateExternCrateReexport(ident), ); } else { if ns == TypeNS { @@ -1397,7 +1386,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { UNUSED_IMPORTS, id, import.span, - format!("the item `{source}` is imported redundantly"), BuiltinLintDiag::RedundantImport(redundant_spans, source), ); */ diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0f585aafdd5..d1d0e336cfe 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -24,7 +24,7 @@ use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::ty::DelegationFnSig; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; -use rustc_session::lint; +use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::parse::feature_err; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -1675,16 +1675,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { return; } LifetimeRibKind::AnonymousWarn(node_id) => { - let msg = if elided { - "`&` without an explicit lifetime name cannot be used here" - } else { - "`'_` cannot be used here" - }; - self.r.lint_buffer.buffer_lint_with_diagnostic( + self.r.lint_buffer.buffer_lint( lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, node_id, lifetime.ident.span, - msg, lint::BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lifetime.ident.span, @@ -1966,11 +1960,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if should_lint { - self.r.lint_buffer.buffer_lint_with_diagnostic( + self.r.lint_buffer.buffer_lint( lint::builtin::ELIDED_LIFETIMES_IN_PATHS, segment_id, elided_lifetime_span, - "hidden lifetime parameters in types are deprecated", lint::BuiltinLintDiag::ElidedLifetimesInPaths( expected_lifetimes, path_span, @@ -4822,7 +4815,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); visit::walk_crate(&mut late_resolution_visitor, krate); for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { - self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label"); + self.lint_buffer.buffer_lint( + lint::builtin::UNUSED_LABELS, + *id, + *span, + BuiltinLintDiag::UnusedLabel, + ); } } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1958fdf1cbc..9daa22f89d2 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -17,6 +17,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, @@ -31,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_middle::ty; @@ -2651,15 +2652,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let deletion_span = if param.bounds.is_empty() { deletion_span() } else { None }; - self.r.lint_buffer.buffer_lint_with_diagnostic( + self.r.lint_buffer.buffer_lint( lint::builtin::SINGLE_USE_LIFETIMES, param.id, param.ident.span, - format!("lifetime parameter `{}` only used once", param.ident), lint::BuiltinLintDiag::SingleUseLifetime { param_span: param.ident.span, use_span: Some((use_span, elidable)), deletion_span, + ident: param.ident, }, ); } @@ -2669,15 +2670,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // if the lifetime originates from expanded code, we won't be able to remove it #104432 if deletion_span.is_some_and(|sp| !sp.in_derive_expansion()) { - self.r.lint_buffer.buffer_lint_with_diagnostic( + self.r.lint_buffer.buffer_lint( lint::builtin::UNUSED_LIFETIMES, param.id, param.ident.span, - format!("lifetime parameter `{}` never used", param.ident), lint::BuiltinLintDiag::SingleUseLifetime { param_span: param.ident.span, use_span: None, deletion_span, + ident: param.ident, }, ); } @@ -2714,8 +2715,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { self.suggest_introducing_lifetime( &mut err, Some(lifetime_ref.ident.name.as_str()), - |err, _, span, message, suggestion| { - err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect); + |err, _, span, message, suggestion, span_suggs| { + err.multipart_suggestion_with_style( + message, + std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), + Applicability::MaybeIncorrect, + if span_suggs.is_empty() { + SuggestionStyle::ShowCode + } else { + SuggestionStyle::ShowAlways + }, + ); true }, ); @@ -2726,13 +2736,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { &self, err: &mut Diag<'_>, name: Option<&str>, - suggest: impl Fn(&mut Diag<'_>, bool, Span, Cow<'static, str>, String) -> bool, + suggest: impl Fn( + &mut Diag<'_>, + bool, + Span, + Cow<'static, str>, + String, + Vec<(Span, String)>, + ) -> bool, ) { let mut suggest_note = true; for rib in self.lifetime_ribs.iter().rev() { let mut should_continue = true; match rib.kind { - LifetimeRibKind::Generics { binder: _, span, kind } => { + LifetimeRibKind::Generics { binder, span, kind } => { // Avoid suggesting placing lifetime parameters on constant items unless the relevant // feature is enabled. Suggest the parent item as a possible location if applicable. if let LifetimeBinderKind::ConstItem = kind @@ -2761,11 +2778,53 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { | LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound ); + + let mut rm_inner_binders: FxIndexSet<Span> = Default::default(); let (span, sugg) = if span.is_empty() { + let mut binder_idents: FxIndexSet<Ident> = Default::default(); + binder_idents.insert(Ident::from_str(name.unwrap_or("'a"))); + + // We need to special case binders in the following situation: + // Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b` + // T: for<'a> Trait<T> + 'b + // ^^^^^^^ remove existing inner binder `for<'a>` + // for<'a, 'b> T: Trait<T> + 'b + // ^^^^^^^^^^^ suggest outer binder `for<'a, 'b>` + if let LifetimeBinderKind::WhereBound = kind + && let Some(ast::WherePredicate::BoundPredicate( + ast::WhereBoundPredicate { bounded_ty, bounds, .. }, + )) = self.diag_metadata.current_where_predicate + && bounded_ty.id == binder + { + for bound in bounds { + if let ast::GenericBound::Trait(poly_trait_ref, _) = bound + && let span = poly_trait_ref + .span + .with_hi(poly_trait_ref.trait_ref.path.span.lo()) + && !span.is_empty() + { + rm_inner_binders.insert(span); + poly_trait_ref.bound_generic_params.iter().for_each(|v| { + binder_idents.insert(v.ident); + }); + } + } + } + + let binders_sugg = binder_idents.into_iter().enumerate().fold( + "".to_string(), + |mut binders, (i, x)| { + if i != 0 { + binders += ", "; + } + binders += x.as_str(); + binders + }, + ); let sugg = format!( "{}<{}>{}", if higher_ranked { "for" } else { "" }, - name.unwrap_or("'a"), + binders_sugg, if higher_ranked { " " } else { "" }, ); (span, sugg) @@ -2780,13 +2839,28 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let sugg = format!("{}, ", name.unwrap_or("'a")); (span, sugg) }; + if higher_ranked { let message = Cow::from(format!( "consider making the {} lifetime-generic with a new `{}` lifetime", kind.descr(), name.unwrap_or("'a"), )); - should_continue = suggest(err, true, span, message, sugg); + should_continue = suggest( + err, + true, + span, + message, + sugg, + if !rm_inner_binders.is_empty() { + rm_inner_binders + .into_iter() + .map(|v| (v, "".to_string())) + .collect::<Vec<_>>() + } else { + vec![] + }, + ); err.note_once( "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", @@ -2794,10 +2868,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } else if let Some(name) = name { let message = Cow::from(format!("consider introducing lifetime `{name}` here")); - should_continue = suggest(err, false, span, message, sugg); + should_continue = suggest(err, false, span, message, sugg, vec![]); } else { let message = Cow::from("consider introducing a named lifetime parameter"); - should_continue = suggest(err, false, span, message, sugg); + should_continue = suggest(err, false, span, message, sugg, vec![]); } } LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break, @@ -3033,11 +3107,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { self.suggest_introducing_lifetime( err, None, - |err, higher_ranked, span, message, intro_sugg| { + |err, higher_ranked, span, message, intro_sugg, _| { err.multipart_suggestion_verbose( message, std::iter::once((span, intro_sugg)) - .chain(spans_suggs.iter().cloned()) + .chain(spans_suggs.clone()) .collect(), Applicability::MaybeIncorrect, ); @@ -3161,11 +3235,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { self.suggest_introducing_lifetime( err, None, - |err, higher_ranked, span, message, intro_sugg| { + |err, higher_ranked, span, message, intro_sugg, _| { err.multipart_suggestion_verbose( message, std::iter::once((span, intro_sugg)) - .chain(spans_suggs.iter().cloned()) + .chain(spans_suggs.clone()) .collect(), Applicability::MaybeIncorrect, ); @@ -3309,7 +3383,6 @@ fn mk_where_bound_predicate( poly_trait_ref: &ast::PolyTraitRef, ty: &Ty, ) -> Option<ast::WhereBoundPredicate> { - use rustc_span::DUMMY_SP; let modified_segments = { let mut segments = path.segments.clone(); let [preceding @ .., second_last, last] = segments.as_mut_slice() else { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 01bcfec4bdc..f4c5ad8f672 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -51,7 +51,7 @@ use rustc_middle::ty::{self, DelegationFnSig, Feed, MainDefinition, RegisteredTo use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; -use rustc_session::lint::LintBuffer; +use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -1860,8 +1860,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if let NameBindingKind::Import { import, binding } = used_binding.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { - let msg = format!("macro `{ident}` is private"); - self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg); + self.lint_buffer().buffer_lint( + PRIVATE_MACRO_USE, + import.root_id, + ident.span, + BuiltinLintDiag::MacroIsPrivate(ident), + ); } // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f8d245f94e5..092eb1ce2ee 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -315,7 +315,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { UNUSED_MACROS, node_id, ident.span, - format!("unused macro definition: `{}`", ident.name), + BuiltinLintDiag::UnusedMacroDefinition(ident.name), ); } for (&(def_id, arm_i), &(ident, rule_span)) in self.unused_macro_rules.iter() { @@ -328,7 +328,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { UNUSED_MACRO_RULES, node_id, rule_span, - format!("rule #{} of macro `{}` is never used", arm_i + 1, ident.name), + BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), ); } } @@ -552,14 +552,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // We are trying to avoid reporting this error if other related errors were reported. if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes { - let msg = match res { - Res::Def(..) => "inner macro attributes are unstable", - Res::NonMacroAttr(..) => "custom inner attributes are unstable", + let is_macro = match res { + Res::Def(..) => true, + Res::NonMacroAttr(..) => false, _ => unreachable!(), }; if soft_custom_inner_attributes_gate { - self.tcx.sess.psess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg); + self.tcx.sess.psess.buffer_lint( + SOFT_UNSTABLE, + path.span, + node_id, + BuiltinLintDiag::InnerAttributeUnstable { is_macro }, + ); } else { + // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::InnerAttributeUnstable`) + let msg = if is_macro { + "inner macro attributes are unstable" + } else { + "custom inner attributes are unstable" + }; feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit(); } } @@ -572,17 +583,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let distance = edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5); - let help = if distance.is_some() { - BuiltinLintDiag::MaybeTypo { span: attribute.span(), name: sym::on_unimplemented } - } else { - BuiltinLintDiag::Normal - }; - self.tcx.sess.psess.buffer_lint_with_diagnostic( + let typo_name = distance.map(|_| sym::on_unimplemented); + + self.tcx.sess.psess.buffer_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, attribute.span(), node_id, - "unknown diagnostic attribute", - help, + BuiltinLintDiag::UnknownDiagnosticAttribute { span: attribute.span(), typo_name }, ); } @@ -782,11 +789,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .invocation_parents .get(&parent_scope.expansion) .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]); - self.lint_buffer.buffer_lint_with_diagnostic( + self.lint_buffer.buffer_lint( LEGACY_DERIVE_HELPERS, node_id, ident.span, - "derive helper attribute is used before it is introduced", BuiltinLintDiag::LegacyDeriveHelpers(binding.span), ); } @@ -836,8 +842,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature)); if !is_allowed(feature) && !allowed_by_implication { let lint_buffer = &mut self.lint_buffer; - let soft_handler = - |lint, span, msg: String| lint_buffer.buffer_lint(lint, node_id, span, msg); + let soft_handler = |lint, span, msg: String| { + lint_buffer.buffer_lint( + lint, + node_id, + span, + BuiltinLintDiag::UnstableFeature( + // FIXME make this translatable + msg.into(), + ), + ) + }; stability::report_unstable( self.tcx.sess, feature, @@ -853,14 +868,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if let Some(depr) = &ext.deprecation { let path = pprust::path_to_string(path); - let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path); - stability::early_report_deprecation( + stability::early_report_macro_deprecation( &mut self.lint_buffer, - message, - depr.suggestion, - lint, + depr, span, node_id, + path, ); } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index f6053f43fbd..df07f81bc45 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -305,32 +305,12 @@ impl ParseSess { lint: &'static Lint, span: impl Into<MultiSpan>, node_id: NodeId, - msg: impl Into<DiagMessage>, - ) { - self.buffered_lints.with_lock(|buffered_lints| { - buffered_lints.push(BufferedEarlyLint { - span: span.into(), - node_id, - msg: msg.into(), - lint_id: LintId::of(lint), - diagnostic: BuiltinLintDiag::Normal, - }); - }); - } - - pub fn buffer_lint_with_diagnostic( - &self, - lint: &'static Lint, - span: impl Into<MultiSpan>, - node_id: NodeId, - msg: impl Into<DiagMessage>, diagnostic: BuiltinLintDiag, ) { self.buffered_lints.with_lock(|buffered_lints| { buffered_lints.push(BufferedEarlyLint { span: span.into(), node_id, - msg: msg.into(), lint_id: LintId::of(lint), diagnostic, }); diff --git a/compiler/rustc_session/src/version.rs b/compiler/rustc_session/src/version.rs index 39e4541349e..e244c77f7f9 100644 --- a/compiler/rustc_session/src/version.rs +++ b/compiler/rustc_session/src/version.rs @@ -1,5 +1,10 @@ use rustc_macros::{current_rustc_version, Decodable, Encodable, HashStable_Generic}; -use std::fmt::{self, Display}; +use std::{ + borrow::Cow, + fmt::{self, Display}, +}; + +use rustc_errors::IntoDiagArg; #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(HashStable_Generic)] @@ -18,3 +23,9 @@ impl Display for RustcVersion { write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch) } } + +impl IntoDiagArg for RustcVersion { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + rustc_errors::DiagArgValue::Str(Cow::Owned(self.to_string())) + } +} diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 89d50b5ffff..281a9b093b9 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -80,8 +80,5 @@ fn create_synthetic_target( customize(spec_map); std::fs::write(&path, serde_json::to_vec_pretty(&spec).unwrap()).unwrap(); - let target = TargetSelection::create_synthetic(&name, path.to_str().unwrap()); - crate::utils::cc_detect::find_target(builder, target); - - target + TargetSelection::create_synthetic(&name, path.to_str().unwrap()) } diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh index 2eafdd0fbc8..09202b1878b 100755 --- a/src/tools/clippy/.github/driver.sh +++ b/src/tools/clippy/.github/driver.sh @@ -2,15 +2,18 @@ set -ex +sysroot="$(rustc --print sysroot)" +case $OS in + Linux) export LD_LIBRARY_PATH="$sysroot/lib" ;; + macOS) export DYLD_FALLBACK_LIBRARY_PATH="$sysroot/lib" ;; + Windows) export PATH="$(cygpath "$sysroot")/bin:$PATH" ;; + *) exit 1 +esac + # Check sysroot handling -sysroot=$(./target/debug/clippy-driver --print sysroot) -test "$sysroot" = "$(rustc --print sysroot)" - -if [[ ${OS} == "Windows" ]]; then - desired_sysroot=C:/tmp -else - desired_sysroot=/tmp -fi +test "$(./target/debug/clippy-driver --print sysroot)" = "$sysroot" + +desired_sysroot="target/sysroot" # Set --sysroot in command line sysroot=$(./target/debug/clippy-driver --sysroot $desired_sysroot --print sysroot) test "$sysroot" = $desired_sysroot diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml index 8179e3e65b5..06bf3b6fdbf 100644 --- a/src/tools/clippy/.github/workflows/clippy.yml +++ b/src/tools/clippy/.github/workflows/clippy.yml @@ -69,6 +69,6 @@ jobs: working-directory: clippy_dev - name: Test clippy-driver - run: | - TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ') - rustup run $TOOLCHAIN bash .github/driver.sh + run: .github/driver.sh + env: + OS: ${{ runner.os }} diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 94515987eba..1f4bec92918 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -116,9 +116,7 @@ jobs: working-directory: clippy_dev - name: Test clippy-driver - run: | - TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ') - rustup run $TOOLCHAIN bash .github/driver.sh + run: .github/driver.sh env: OS: ${{ runner.os }} diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 9c9ea114081..d5115f70f66 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5249,6 +5249,7 @@ Released 2018-09-13 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression +[`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons @@ -5447,6 +5448,7 @@ Released 2018-09-13 [`little_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#little_endian_bytes [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal +[`macro_metavars_in_unsafe`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert @@ -5702,6 +5704,7 @@ Released 2018-09-13 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro +[`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts @@ -5908,6 +5911,7 @@ Released 2018-09-13 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons [`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake +[`while_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_float [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator @@ -5939,8 +5943,10 @@ Released 2018-09-13 [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings +[`allow-panic-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-panic-in-tests [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception +[`allow-renamed-params-for`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-renamed-params-for [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests [`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles @@ -6002,4 +6008,5 @@ Released 2018-09-13 [`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold [`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold [`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports +[`warn-unsafe-macro-metavars-in-private-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-unsafe-macro-metavars-in-private-macros <!-- end autogenerated links to configuration documentation --> diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index f6af9810ca1..c8223007df7 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -101,6 +101,16 @@ Whether to allow `r#""#` when `r""` can be used * [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes) +## `allow-panic-in-tests` +Whether `panic` should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`panic`](https://rust-lang.github.io/rust-clippy/master/index.html#panic) + + ## `allow-print-in-tests` Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` @@ -122,6 +132,28 @@ Whether to allow module inception if it's not public. * [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception) +## `allow-renamed-params-for` +List of trait paths to ignore when checking renamed function parameters. + +#### Example + +```toml +allow-renamed-params-for = [ "std::convert::From" ] +``` + +#### Noteworthy + +- By default, the following traits are ignored: `From`, `TryFrom`, `FromStr` +- `".."` can be used as part of the list to indicate that the configured values should be appended to the +default configuration of Clippy. By default, any configuration will replace the default value. + +**Default Value:** `["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"]` + +--- +**Affected lints:** +* [`renamed_function_params`](https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params) + + ## `allow-unwrap-in-tests` Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` @@ -900,3 +932,13 @@ Whether to allow certain wildcard imports (prelude, super in tests). * [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) +## `warn-unsafe-macro-metavars-in-private-macros` +Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros. + +**Default Value:** `false` + +--- +**Affected lints:** +* [`macro_metavars_in_unsafe`](https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe) + + diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 5cfcbdb57d7..cfdf620b7d0 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -40,6 +40,8 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"]; +const DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS: &[&str] = + &["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"]; /// Conf with parse errors #[derive(Default)] @@ -455,6 +457,10 @@ define_Conf! { /// /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` (allow_unwrap_in_tests: bool = false), + /// Lint: PANIC. + /// + /// Whether `panic` should be allowed in test functions or `#[cfg(test)]` + (allow_panic_in_tests: bool = false), /// Lint: DBG_MACRO. /// /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` @@ -613,6 +619,27 @@ define_Conf! { /// - Use `".."` as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value (allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()), + /// Lint: RENAMED_FUNCTION_PARAMS. + /// + /// List of trait paths to ignore when checking renamed function parameters. + /// + /// #### Example + /// + /// ```toml + /// allow-renamed-params-for = [ "std::convert::From" ] + /// ``` + /// + /// #### Noteworthy + /// + /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr` + /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the + /// default configuration of Clippy. By default, any configuration will replace the default value. + (allow_renamed_params_for: Vec<String> = + DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()), + /// Lint: MACRO_METAVARS_IN_UNSAFE. + /// + /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros. + (warn_unsafe_macro_metavars_in_private_macros: bool = false), } /// Search for the configuration file. @@ -674,6 +701,10 @@ fn deserialize(file: &SourceFile) -> TryConf { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES); + extend_vec_if_indicator_present( + &mut conf.conf.allow_renamed_params_for, + DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS, + ); // TODO: THIS SHOULD BE TESTED, this comment will be gone soon if conf.conf.allowed_idents_below_min_chars.contains("..") { conf.conf diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index 14808440d48..a3e7d0c3fa5 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -26,7 +26,8 @@ msrv_aliases! { 1,63,0 { CLONE_INTO } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } - 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } + 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } + 1,56,0 { CONST_FN_UNION } 1,55,0 { SEEK_REWIND } 1,54,0 { INTO_KEYS } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index 42a953039b1..4104e7d94f1 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "clippy_dev" +description = "Clippy developer tooling" version = "0.0.1" edition = "2021" [dependencies] aho-corasick = "1.0" -clap = "4.1.4" +clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.6" diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index 397a0e99082..366b52b25df 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -2,350 +2,292 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] -use clap::{Arg, ArgAction, ArgMatches, Command}; +use clap::{Args, Parser, Subcommand}; use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints}; -use indoc::indoc; use std::convert::Infallible; fn main() { - let matches = get_clap_config(); + let dev = Dev::parse(); - match matches.subcommand() { - Some(("bless", _)) => { + match dev.command { + DevCommand::Bless => { eprintln!("use `cargo bless` to automatically replace `.stderr` and `.fixed` files as tests are being run"); }, - Some(("dogfood", matches)) => { - dogfood::dogfood( - matches.get_flag("fix"), - matches.get_flag("allow-dirty"), - matches.get_flag("allow-staged"), - ); - }, - Some(("fmt", matches)) => { - fmt::run(matches.get_flag("check"), matches.get_flag("verbose")); - }, - Some(("update_lints", matches)) => { - if matches.get_flag("print-only") { + DevCommand::Dogfood { + fix, + allow_dirty, + allow_staged, + } => dogfood::dogfood(fix, allow_dirty, allow_staged), + DevCommand::Fmt { check, verbose } => fmt::run(check, verbose), + DevCommand::UpdateLints { print_only, check } => { + if print_only { update_lints::print_lints(); - } else if matches.get_flag("check") { + } else if check { update_lints::update(update_lints::UpdateMode::Check); } else { update_lints::update(update_lints::UpdateMode::Change); } }, - Some(("new_lint", matches)) => { - match new_lint::create( - matches.get_one::<String>("pass").unwrap(), - matches.get_one::<String>("name"), - matches.get_one::<String>("category").map(String::as_str), - matches.get_one::<String>("type").map(String::as_str), - matches.get_flag("msrv"), - ) { - Ok(()) => update_lints::update(update_lints::UpdateMode::Change), - Err(e) => eprintln!("Unable to create lint: {e}"), - } + DevCommand::NewLint { + pass, + name, + category, + r#type, + msrv, + } => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) { + Ok(()) => update_lints::update(update_lints::UpdateMode::Change), + Err(e) => eprintln!("Unable to create lint: {e}"), }, - Some(("setup", sub_command)) => match sub_command.subcommand() { - Some(("git-hook", matches)) => { - if matches.get_flag("remove") { - setup::git_hook::remove_hook(); + DevCommand::Setup(SetupCommand { subcommand }) => match subcommand { + SetupSubcommand::Intellij { remove, repo_path } => { + if remove { + setup::intellij::remove_rustc_src(); } else { - setup::git_hook::install_hook(matches.get_flag("force-override")); + setup::intellij::setup_rustc_src(&repo_path); } }, - Some(("intellij", matches)) => { - if matches.get_flag("remove") { - setup::intellij::remove_rustc_src(); + SetupSubcommand::GitHook { remove, force_override } => { + if remove { + setup::git_hook::remove_hook(); } else { - setup::intellij::setup_rustc_src( - matches - .get_one::<String>("rustc-repo-path") - .expect("this field is mandatory and therefore always valid"), - ); + setup::git_hook::install_hook(force_override); } }, - Some(("toolchain", matches)) => { - setup::toolchain::create( - matches.get_flag("force"), - matches.get_flag("release"), - matches.get_one::<String>("name").unwrap(), - ); - }, - Some(("vscode-tasks", matches)) => { - if matches.get_flag("remove") { + SetupSubcommand::Toolchain { force, release, name } => setup::toolchain::create(force, release, &name), + SetupSubcommand::VscodeTasks { remove, force_override } => { + if remove { setup::vscode::remove_tasks(); } else { - setup::vscode::install_tasks(matches.get_flag("force-override")); + setup::vscode::install_tasks(force_override); } }, - _ => {}, - }, - Some(("remove", sub_command)) => match sub_command.subcommand() { - Some(("git-hook", _)) => setup::git_hook::remove_hook(), - Some(("intellij", _)) => setup::intellij::remove_rustc_src(), - Some(("vscode-tasks", _)) => setup::vscode::remove_tasks(), - _ => {}, - }, - Some(("serve", matches)) => { - let port = *matches.get_one::<u16>("port").unwrap(); - let lint = matches.get_one::<String>("lint"); - serve::run(port, lint); }, - Some(("lint", matches)) => { - let path = matches.get_one::<String>("path").unwrap(); - let args = matches.get_many::<String>("args").into_iter().flatten(); - lint::run(path, args); + DevCommand::Remove(RemoveCommand { subcommand }) => match subcommand { + RemoveSubcommand::Intellij => setup::intellij::remove_rustc_src(), + RemoveSubcommand::GitHook => setup::git_hook::remove_hook(), + RemoveSubcommand::VscodeTasks => setup::vscode::remove_tasks(), }, - Some(("rename_lint", matches)) => { - let old_name = matches.get_one::<String>("old_name").unwrap(); - let new_name = matches.get_one::<String>("new_name").unwrap_or(old_name); - let uplift = matches.get_flag("uplift"); - update_lints::rename(old_name, new_name, uplift); - }, - Some(("deprecate", matches)) => { - let name = matches.get_one::<String>("name").unwrap(); - let reason = matches.get_one("reason"); - update_lints::deprecate(name, reason); - }, - _ => {}, + DevCommand::Serve { port, lint } => serve::run(port, lint), + DevCommand::Lint { path, args } => lint::run(&path, args.iter()), + DevCommand::RenameLint { + old_name, + new_name, + uplift, + } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift), + DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, reason.as_deref()), } } -fn get_clap_config() -> ArgMatches { - Command::new("Clippy developer tooling") - .arg_required_else_help(true) - .subcommands([ - Command::new("bless").about("bless the test output changes").arg( - Arg::new("ignore-timestamp") - .long("ignore-timestamp") - .action(ArgAction::SetTrue) - .help("Include files updated before clippy was built"), - ), - Command::new("dogfood").about("Runs the dogfood test").args([ - Arg::new("fix") - .long("fix") - .action(ArgAction::SetTrue) - .help("Apply the suggestions when possible"), - Arg::new("allow-dirty") - .long("allow-dirty") - .action(ArgAction::SetTrue) - .help("Fix code even if the working directory has changes") - .requires("fix"), - Arg::new("allow-staged") - .long("allow-staged") - .action(ArgAction::SetTrue) - .help("Fix code even if the working directory has staged changes") - .requires("fix"), - ]), - Command::new("fmt") - .about("Run rustfmt on all projects and tests") - .args([ - Arg::new("check") - .long("check") - .action(ArgAction::SetTrue) - .help("Use the rustfmt --check option"), - Arg::new("verbose") - .short('v') - .long("verbose") - .action(ArgAction::SetTrue) - .help("Echo commands run"), - ]), - Command::new("update_lints") - .about("Updates lint registration and information from the source code") - .long_about( - "Makes sure that:\n \ - * the lint count in README.md is correct\n \ - * the changelog contains markdown link references at the bottom\n \ - * all lint groups include the correct lints\n \ - * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \ - * all lints are registered in the lint store", - ) - .args([ - Arg::new("print-only") - .long("print-only") - .action(ArgAction::SetTrue) - .help( - "Print a table of lints to STDOUT. \ - This does not include deprecated and internal lints. \ - (Does not modify any files)", - ), - Arg::new("check") - .long("check") - .action(ArgAction::SetTrue) - .help("Checks that `cargo dev update_lints` has been run. Used on CI."), - ]), - Command::new("new_lint") - .about("Create new lint and run `cargo dev update_lints`") - .args([ - Arg::new("pass") - .short('p') - .long("pass") - .help("Specify whether the lint runs during the early or late pass") - .value_parser(["early", "late"]) - .conflicts_with("type") - .default_value("late"), - Arg::new("name") - .short('n') - .long("name") - .help("Name of the new lint in snake case, ex: fn_too_long") - .required(true) - .value_parser(|name: &str| Ok::<_, Infallible>(name.replace('-', "_"))), - Arg::new("category") - .short('c') - .long("category") - .help("What category the lint belongs to") - .default_value("nursery") - .value_parser([ - "style", - "correctness", - "suspicious", - "complexity", - "perf", - "pedantic", - "restriction", - "cargo", - "nursery", - "internal", - ]), - Arg::new("type").long("type").help("What directory the lint belongs in"), - Arg::new("msrv") - .long("msrv") - .action(ArgAction::SetTrue) - .help("Add MSRV config code to the lint"), - ]), - Command::new("setup") - .about("Support for setting up your personal development environment") - .arg_required_else_help(true) - .subcommands([ - Command::new("git-hook") - .about("Add a pre-commit git hook that formats your code to make it look pretty") - .args([ - Arg::new("remove") - .long("remove") - .action(ArgAction::SetTrue) - .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), - Arg::new("force-override") - .long("force-override") - .short('f') - .action(ArgAction::SetTrue) - .help("Forces the override of an existing git pre-commit hook"), - ]), - Command::new("intellij") - .about("Alter dependencies so Intellij Rust can find rustc internals") - .args([ - Arg::new("remove") - .long("remove") - .action(ArgAction::SetTrue) - .help("Remove the dependencies added with 'cargo dev setup intellij'"), - Arg::new("rustc-repo-path") - .long("repo-path") - .short('r') - .help("The path to a rustc repo that will be used for setting the dependencies") - .value_name("path") - .conflicts_with("remove") - .required(true), - ]), - Command::new("toolchain") - .about("Install a rustup toolchain pointing to the local clippy build") - .args([ - Arg::new("force") - .long("force") - .short('f') - .action(ArgAction::SetTrue) - .help("Override an existing toolchain"), - Arg::new("release") - .long("release") - .short('r') - .action(ArgAction::SetTrue) - .help("Point to --release clippy binaries"), - Arg::new("name") - .long("name") - .default_value("clippy") - .help("The name of the created toolchain"), - ]), - Command::new("vscode-tasks") - .about("Add several tasks to vscode for formatting, validation and testing") - .args([ - Arg::new("remove") - .long("remove") - .action(ArgAction::SetTrue) - .help("Remove the tasks added with 'cargo dev setup vscode-tasks'"), - Arg::new("force-override") - .long("force-override") - .short('f') - .action(ArgAction::SetTrue) - .help("Forces the override of existing vscode tasks"), - ]), - ]), - Command::new("remove") - .about("Support for undoing changes done by the setup command") - .arg_required_else_help(true) - .subcommands([ - Command::new("git-hook").about("Remove any existing pre-commit git hook"), - Command::new("vscode-tasks").about("Remove any existing vscode tasks"), - Command::new("intellij").about("Removes rustc source paths added via `cargo dev setup intellij`"), - ]), - Command::new("serve") - .about("Launch a local 'ALL the Clippy Lints' website in a browser") - .args([ - Arg::new("port") - .long("port") - .short('p') - .help("Local port for the http server") - .default_value("8000") - .value_parser(clap::value_parser!(u16)), - Arg::new("lint").help("Which lint's page to load initially (optional)"), - ]), - Command::new("lint") - .about("Manually run clippy on a file or package") - .after_help(indoc! {" - EXAMPLES - Lint a single file: - cargo dev lint tests/ui/attrs.rs +#[derive(Parser)] +#[command(name = "dev", about)] +struct Dev { + #[command(subcommand)] + command: DevCommand, +} - Lint a package directory: - cargo dev lint tests/ui-cargo/wildcard_dependencies/fail - cargo dev lint ~/my-project +#[derive(Subcommand)] +enum DevCommand { + /// Bless the test output changes + Bless, + /// Runs the dogfood test + Dogfood { + #[arg(long)] + /// Apply the suggestions when possible + fix: bool, + #[arg(long, requires = "fix")] + /// Fix code even if the working directory has changes + allow_dirty: bool, + #[arg(long, requires = "fix")] + /// Fix code even if the working directory has staged changes + allow_staged: bool, + }, + /// Run rustfmt on all projects and tests + Fmt { + #[arg(long)] + /// Use the rustfmt --check option + check: bool, + #[arg(short, long)] + /// Echo commands run + verbose: bool, + }, + #[command(name = "update_lints")] + /// Updates lint registration and information from the source code + /// + /// Makes sure that: {n} + /// * the lint count in README.md is correct {n} + /// * the changelog contains markdown link references at the bottom {n} + /// * all lint groups include the correct lints {n} + /// * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod` {n} + /// * all lints are registered in the lint store + UpdateLints { + #[arg(long)] + /// Print a table of lints to STDOUT + /// + /// This does not include deprecated and internal lints. (Does not modify any files) + print_only: bool, + #[arg(long)] + /// Checks that `cargo dev update_lints` has been run. Used on CI. + check: bool, + }, + #[command(name = "new_lint")] + /// Create a new lint and run `cargo dev update_lints` + NewLint { + #[arg(short, long, value_parser = ["early", "late"], conflicts_with = "type", default_value = "late")] + /// Specify whether the lint runs during the early or late pass + pass: String, + #[arg( + short, + long, + value_parser = |name: &str| Ok::<_, Infallible>(name.replace('-', "_")), + )] + /// Name of the new lint in snake case, ex: `fn_too_long` + name: String, + #[arg( + short, + long, + value_parser = [ + "style", + "correctness", + "suspicious", + "complexity", + "perf", + "pedantic", + "restriction", + "cargo", + "nursery", + "internal", + ], + default_value = "nursery", + )] + /// What category the lint belongs to + category: String, + #[arg(long)] + /// What directory the lint belongs in + r#type: Option<String>, + #[arg(long)] + /// Add MSRV config code to the lint + msrv: bool, + }, + /// Support for setting up your personal development environment + Setup(SetupCommand), + /// Support for removing changes done by the setup command + Remove(RemoveCommand), + /// Launch a local 'ALL the Clippy Lints' website in a browser + Serve { + #[arg(short, long, default_value = "8000")] + /// Local port for the http server + port: u16, + #[arg(long)] + /// Which lint's page to load initially (optional) + lint: Option<String>, + }, + #[allow(clippy::doc_markdown)] + /// Manually run clippy on a file or package + /// + /// ## Examples + /// + /// Lint a single file: {n} + /// cargo dev lint tests/ui/attrs.rs + /// + /// Lint a package directory: {n} + /// cargo dev lint tests/ui-cargo/wildcard_dependencies/fail {n} + /// cargo dev lint ~/my-project + /// + /// Run rustfix: {n} + /// cargo dev lint ~/my-project -- --fix + /// + /// Set lint levels: {n} + /// cargo dev lint file.rs -- -W clippy::pedantic {n} + /// cargo dev lint ~/my-project -- -- -W clippy::pedantic + Lint { + /// The path to a file or package directory to lint + path: String, + /// Pass extra arguments to cargo/clippy-driver + args: Vec<String>, + }, + #[command(name = "rename_lint")] + /// Rename a lint + RenameLint { + /// The name of the lint to rename + old_name: String, + #[arg(required_unless_present = "uplift")] + /// The new name of the lint + new_name: Option<String>, + #[arg(long)] + /// This lint will be uplifted into rustc + uplift: bool, + }, + /// Deprecate the given lint + Deprecate { + /// The name of the lint to deprecate + name: String, + #[arg(long, short)] + /// The reason for deprecation + reason: Option<String>, + }, +} - Run rustfix: - cargo dev lint ~/my-project -- --fix +#[derive(Args)] +struct SetupCommand { + #[command(subcommand)] + subcommand: SetupSubcommand, +} + +#[derive(Subcommand)] +enum SetupSubcommand { + /// Alter dependencies so Intellij Rust can find rustc internals + Intellij { + #[arg(long)] + /// Remove the dependencies added with 'cargo dev setup intellij' + remove: bool, + #[arg(long, short, conflicts_with = "remove")] + /// The path to a rustc repo that will be used for setting the dependencies + repo_path: String, + }, + /// Add a pre-commit git hook that formats your code to make it look pretty + GitHook { + #[arg(long)] + /// Remove the pre-commit hook added with 'cargo dev setup git-hook' + remove: bool, + #[arg(long, short)] + /// Forces the override of an existing git pre-commit hook + force_override: bool, + }, + /// Install a rustup toolchain pointing to the local clippy build + Toolchain { + #[arg(long, short)] + /// Override an existing toolchain + force: bool, + #[arg(long, short)] + /// Point to --release clippy binary + release: bool, + #[arg(long, default_value = "clippy")] + /// Name of the toolchain + name: String, + }, + /// Add several tasks to vscode for formatting, validation and testing + VscodeTasks { + #[arg(long)] + /// Remove the tasks added with 'cargo dev setup vscode-tasks' + remove: bool, + #[arg(long, short)] + /// Forces the override of existing vscode tasks + force_override: bool, + }, +} + +#[derive(Args)] +struct RemoveCommand { + #[command(subcommand)] + subcommand: RemoveSubcommand, +} - Set lint levels: - cargo dev lint file.rs -- -W clippy::pedantic - cargo dev lint ~/my-project -- -- -W clippy::pedantic - "}) - .args([ - Arg::new("path") - .required(true) - .help("The path to a file or package directory to lint"), - Arg::new("args") - .action(ArgAction::Append) - .help("Pass extra arguments to cargo/clippy-driver"), - ]), - Command::new("rename_lint").about("Renames the given lint").args([ - Arg::new("old_name") - .index(1) - .required(true) - .help("The name of the lint to rename"), - Arg::new("new_name") - .index(2) - .required_unless_present("uplift") - .help("The new name of the lint"), - Arg::new("uplift") - .long("uplift") - .action(ArgAction::SetTrue) - .help("This lint will be uplifted into rustc"), - ]), - Command::new("deprecate").about("Deprecates the given lint").args([ - Arg::new("name") - .index(1) - .required(true) - .help("The name of the lint to deprecate"), - Arg::new("reason") - .long("reason") - .short('r') - .help("The reason for deprecation"), - ]), - ]) - .get_matches() +#[derive(Subcommand)] +enum RemoveSubcommand { + /// Remove the dependencies added with 'cargo dev setup intellij' + Intellij, + /// Remove the pre-commit git hook + GitHook, + /// Remove the tasks added with 'cargo dev setup vscode-tasks' + VscodeTasks, } diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 2940d56350f..b6481dde4dd 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -36,22 +36,16 @@ impl<T> Context for io::Result<T> { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -pub fn create( - pass: &String, - lint_name: Option<&String>, - category: Option<&str>, - mut ty: Option<&str>, - msrv: bool, -) -> io::Result<()> { - if category == Some("cargo") && ty.is_none() { +pub fn create(pass: &str, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> { + if category == "cargo" && ty.is_none() { // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo` ty = Some("cargo"); } let lint = LintData { pass, - name: lint_name.expect("`name` argument is validated by clap"), - category: category.expect("`category` argument is validated by clap"), + name, + category, ty, project_root: clippy_project_root(), }; diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs index ea925f6709f..4a4261d1a1e 100644 --- a/src/tools/clippy/clippy_dev/src/serve.rs +++ b/src/tools/clippy/clippy_dev/src/serve.rs @@ -8,7 +8,7 @@ use std::{env, thread}; /// # Panics /// /// Panics if the python commands could not be spawned -pub fn run(port: u16, lint: Option<&String>) -> ! { +pub fn run(port: u16, lint: Option<String>) -> ! { let mut url = Some(match lint { None => format!("http://localhost:{port}"), Some(lint) => format!("http://localhost:{port}/#{lint}"), diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 625b1339591..45353901c98 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -314,7 +314,7 @@ const DEFAULT_DEPRECATION_REASON: &str = "default deprecation note"; /// # Panics /// /// If a file path could not read from or written to -pub fn deprecate(name: &str, reason: Option<&String>) { +pub fn deprecate(name: &str, reason: Option<&str>) { fn finish( (lints, mut deprecated_lints, renamed_lints): (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>), name: &str, @@ -335,7 +335,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) { println!("note: you must run `cargo uitest` to update the test results"); } - let reason = reason.map_or(DEFAULT_DEPRECATION_REASON, String::as_str); + let reason = reason.unwrap_or(DEFAULT_DEPRECATION_REASON); let name_lower = name.to_lowercase(); let name_upper = name.to_uppercase(); diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index f0dafb1ae0d..e94a6f3e3fc 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -2,15 +2,15 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::HirNode; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_trait_method, path_to_local}; +use clippy_utils::{is_trait_method, local_is_initialized, path_to_local}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, Expr, ExprKind, Node}; +use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Instance, Mutability}; use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::symbol::sym; -use rustc_span::ExpnKind; +use rustc_span::{ExpnKind, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -36,6 +36,7 @@ declare_clippy_lint! { /// Use instead: /// ```rust /// struct Thing; + /// /// impl Clone for Thing { /// fn clone(&self) -> Self { todo!() } /// fn clone_from(&mut self, other: &Self) { todo!() } @@ -47,7 +48,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub ASSIGNING_CLONES, - perf, + pedantic, "assigning the result of cloning may be inefficient" } @@ -67,7 +68,8 @@ impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); impl<'tcx> LateLintPass<'tcx> for AssigningClones { fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) { // Do not fire the lint in macros - let expn_data = assign_expr.span().ctxt().outer_expn_data(); + let ctxt = assign_expr.span().ctxt(); + let expn_data = ctxt.outer_expn_data(); match expn_data.kind { ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return, ExpnKind::Root => {}, @@ -82,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { }; if is_ok_to_suggest(cx, lhs, &call, &self.msrv) { - suggest(cx, assign_expr, lhs, &call); + suggest(cx, ctxt, assign_expr, lhs, &call); } } @@ -163,9 +165,7 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC // TODO: This check currently bails if the local variable has no initializer. // That is overly conservative - the lint should fire even if there was no initializer, // but the variable has been initialized before `lhs` was evaluated. - if let Some(Node::LetStmt(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p)) - && local.init.is_none() - { + if !local_is_initialized(cx, local) { return false; } } @@ -222,14 +222,20 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC implemented_fns.contains_key(&provided_fn.def_id) } -fn suggest<'tcx>(cx: &LateContext<'tcx>, assign_expr: &Expr<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) { +fn suggest<'tcx>( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + assign_expr: &Expr<'tcx>, + lhs: &Expr<'tcx>, + call: &CallCandidate<'tcx>, +) { span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| { let mut applicability = Applicability::Unspecified; diag.span_suggestion( assign_expr.span, call.suggestion_msg(), - call.suggested_replacement(cx, lhs, &mut applicability), + call.suggested_replacement(cx, ctxt, lhs, &mut applicability), applicability, ); }); @@ -275,6 +281,7 @@ impl<'tcx> CallCandidate<'tcx> { fn suggested_replacement( &self, cx: &LateContext<'tcx>, + ctxt: SyntaxContext, lhs: &Expr<'tcx>, applicability: &mut Applicability, ) -> String { @@ -294,7 +301,7 @@ impl<'tcx> CallCandidate<'tcx> { // Determine whether we need to reference the argument to clone_from(). let clone_receiver_type = cx.typeck_results().expr_ty(receiver); let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver); - let mut arg_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability); + let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); if clone_receiver_type != clone_receiver_adj_type { // The receiver may have been a value type, so we need to add an `&` to // be sure the argument to clone_from will be a reference. @@ -312,7 +319,7 @@ impl<'tcx> CallCandidate<'tcx> { Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr() }; // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. - let rhs_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability); + let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); format!("Clone::clone_from({self_sugg}, {rhs_sugg})") }, @@ -341,11 +348,11 @@ impl<'tcx> CallCandidate<'tcx> { match self.kind { CallKind::MethodCall { receiver } => { - let receiver_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability); + let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); format!("{receiver_sugg}.clone_into({rhs_sugg})") }, CallKind::FunctionCall { self_arg, .. } => { - let self_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability); + let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") }, } diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index 736ee48641d..40a1c4e2884 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -36,9 +36,10 @@ fn check_duplicated_attr( } let Some(ident) = attr.ident() else { return }; let name = ident.name; - if name == sym::doc || name == sym::cfg_attr { + if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented { // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg // conditions are the same. + // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. return; } if let Some(direct_parent) = parent.last() diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 8f47bc7653b..39f40607799 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -61,11 +61,21 @@ declare_clippy_lint! { /// /// This lint permits lint attributes for lints emitted on the items themself. /// For `use` items these lints are: + /// * ambiguous_glob_reexports + /// * dead_code /// * deprecated + /// * hidden_glob_reexports /// * unreachable_pub - /// * unused_imports + /// * unused + /// * unused_braces + /// * unused_import_braces + /// * clippy::disallowed_types /// * clippy::enum_glob_use /// * clippy::macro_use_imports + /// * clippy::module_name_repetitions + /// * clippy::redundant_pub_crate + /// * clippy::single_component_path_imports + /// * clippy::unsafe_removed_from_name /// * clippy::wildcard_imports /// /// For `extern crate` items these lints are: diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 7575f502a7c..f0868231d01 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -2,6 +2,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{first_line_of_span, snippet_opt}; +use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LintContext}; @@ -20,26 +21,40 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) for lint in lint_list { match item.kind { ItemKind::Use(..) => { - if is_word(lint, sym::unused_imports) - || is_word(lint, sym::deprecated) - || is_word(lint, sym!(unreachable_pub)) - || is_word(lint, sym!(unused)) - || is_word(lint, sym!(unused_import_braces)) - || extract_clippy_lint(lint).map_or(false, |s| { - matches!( - s.as_str(), - "wildcard_imports" - | "enum_glob_use" - | "redundant_pub_crate" - | "macro_use_imports" - | "unsafe_removed_from_name" - | "module_name_repetitions" - | "single_component_path_imports" - ) - }) + if let NestedMetaItem::MetaItem(meta_item) = lint + && meta_item.is_word() + && let Some(ident) = meta_item.ident() + && matches!( + ident.name.as_str(), + "ambiguous_glob_reexports" + | "dead_code" + | "deprecated" + | "hidden_glob_reexports" + | "unreachable_pub" + | "unused" + | "unused_braces" + | "unused_import_braces" + | "unused_imports" + ) { return; } + + if extract_clippy_lint(lint).is_some_and(|symbol| { + matches!( + symbol.as_str(), + "wildcard_imports" + | "enum_glob_use" + | "redundant_pub_crate" + | "macro_use_imports" + | "unsafe_removed_from_name" + | "module_name_repetitions" + | "single_component_path_imports" + | "disallowed_types" + ) + }) { + return; + } }, ItemKind::ExternCrate(..) => { if is_word(lint, sym::unused_imports) && skip_unused_imports { diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs index a3291c9da10..0d9eaac882f 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs @@ -49,7 +49,7 @@ impl LintConfig { type LintTable = BTreeMap<Spanned<String>, Spanned<LintConfig>>; -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Default)] struct Lints { #[serde(default)] rust: LintTable, @@ -57,9 +57,18 @@ struct Lints { clippy: LintTable, } +#[derive(Deserialize, Debug, Default)] +struct Workspace { + #[serde(default)] + lints: Lints, +} + #[derive(Deserialize, Debug)] struct CargoToml { + #[serde(default)] lints: Lints, + #[serde(default)] + workspace: Workspace, } #[derive(Default, Debug)] @@ -164,5 +173,7 @@ pub fn check(cx: &LateContext<'_>) { check_table(cx, cargo_toml.lints.rust, &rustc_groups, &file); check_table(cx, cargo_toml.lints.clippy, &clippy_groups, &file); + check_table(cx, cargo_toml.workspace.lints.rust, &rustc_groups, &file); + check_table(cx, cargo_toml.workspace.lints.clippy, &clippy_groups, &file); } } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 2b6e17dc103..864489ee3fc 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -255,8 +255,10 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { /// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`], /// where the result depends on: +/// /// - the number of negative values in the entire expression, or /// - the number of negative values on the left hand side of the expression. +/// /// Ignores overflow. /// /// @@ -303,8 +305,10 @@ fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { } /// Peels binary operators such as [`BinOpKind::Add`], where the result depends on: +/// /// - all the expressions being positive, or /// - all the expressions being negative. +/// /// Ignores overflow. /// /// Expressions using other operators are preserved, so we can try to evaluate them later. diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 5ff7d8e5134..df2ef465700 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -140,6 +140,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::disallowed_names::DISALLOWED_NAMES_INFO, crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO, crate::disallowed_types::DISALLOWED_TYPES_INFO, + crate::doc::DOC_LAZY_CONTINUATION_INFO, crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, crate::doc::EMPTY_DOCS_INFO, @@ -205,6 +206,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::functions::MUST_USE_CANDIDATE_INFO, crate::functions::MUST_USE_UNIT_INFO, crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO, + crate::functions::RENAMED_FUNCTION_PARAMS_INFO, crate::functions::RESULT_LARGE_ERR_INFO, crate::functions::RESULT_UNIT_ERR_INFO, crate::functions::TOO_MANY_ARGUMENTS_INFO, @@ -291,9 +293,11 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::SAME_ITEM_PUSH_INFO, crate::loops::SINGLE_ELEMENT_LOOP_INFO, crate::loops::UNUSED_ENUMERATE_INDEX_INFO, + crate::loops::WHILE_FLOAT_INFO, crate::loops::WHILE_IMMUTABLE_CONDITION_INFO, crate::loops::WHILE_LET_LOOP_INFO, crate::loops::WHILE_LET_ON_ITERATOR_INFO, + crate::macro_metavars_in_unsafe::MACRO_METAVARS_IN_UNSAFE_INFO, crate::macro_use::MACRO_USE_IMPORTS_INFO, crate::main_recursion::MAIN_RECURSION_INFO, crate::manual_assert::MANUAL_ASSERT_INFO, diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs new file mode 100644 index 00000000000..38bc58a5501 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs @@ -0,0 +1,95 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use itertools::Itertools; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_lint::LateContext; +use rustc_span::{BytePos, Span}; +use std::ops::Range; + +use super::DOC_LAZY_CONTINUATION; + +fn map_container_to_text(c: &super::Container) -> &'static str { + match c { + super::Container::Blockquote => "> ", + // numbered list can have up to nine digits, plus the dot, plus four spaces on either side + super::Container::List(indent) => &" "[0..*indent], + } +} + +// TODO: Adjust the parameters as necessary +pub(super) fn check( + cx: &LateContext<'_>, + doc: &str, + range: Range<usize>, + mut span: Span, + containers: &[super::Container], +) { + if doc[range.clone()].contains('\t') { + // We don't do tab stops correctly. + return; + } + + let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count(); + let blockquote_level = containers + .iter() + .filter(|c| matches!(c, super::Container::Blockquote)) + .count(); + let lcount = doc[range.clone()].chars().filter(|c| *c == ' ').count(); + let list_indentation = containers + .iter() + .map(|c| { + if let super::Container::List(indent) = c { + *indent + } else { + 0 + } + }) + .sum(); + if ccount < blockquote_level || lcount < list_indentation { + let msg = if ccount < blockquote_level { + "doc quote missing `>` marker" + } else { + "doc list item missing indentation" + }; + span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { + if ccount == 0 && blockquote_level == 0 { + // simpler suggestion style for indentation + let indent = list_indentation - lcount; + diag.span_suggestion_with_style( + span.shrink_to_hi(), + "indent this line", + std::iter::repeat(" ").take(indent).join(""), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + diag.help("if this is supposed to be its own paragraph, add a blank line"); + return; + } + let mut doc_start_range = &doc[range]; + let mut suggested = String::new(); + for c in containers { + let text = map_container_to_text(c); + if doc_start_range.starts_with(text) { + doc_start_range = &doc_start_range[text.len()..]; + span = span + .with_lo(span.lo() + BytePos(u32::try_from(text.len()).expect("text is not 2**32 or bigger"))); + } else if matches!(c, super::Container::Blockquote) + && let Some(i) = doc_start_range.find('>') + { + doc_start_range = &doc_start_range[i + 1..]; + span = + span.with_lo(span.lo() + BytePos(u32::try_from(i).expect("text is not 2**32 or bigger") + 1)); + } else { + suggested.push_str(text); + } + } + diag.span_suggestion_with_style( + span, + "add markers to start of line", + suggested, + Applicability::MachineApplicable, + SuggestionStyle::ShowAlways, + ); + diag.help("if this not intended to be a quote at all, escape it with `\\>`"); + }); + } +} diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs index 36ba19698c7..010fab803d9 100644 --- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs +++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs @@ -1,3 +1,4 @@ +use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{is_doc_hidden, return_ty}; @@ -6,15 +7,13 @@ use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::{sym, Span}; -use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; - pub fn check( cx: &LateContext<'_>, owner_id: OwnerId, sig: FnSig<'_>, headers: DocHeaders, body_id: Option<BodyId>, - panic_span: Option<Span>, + panic_info: Option<(Span, bool)>, check_private_items: bool, ) { if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) { @@ -48,13 +47,13 @@ pub fn check( ), _ => (), } - if !headers.panics && panic_span.is_some() { + if !headers.panics && panic_info.map_or(false, |el| !el.1) { span_lint_and_note( cx, MISSING_PANICS_DOC, span, "docs for function which may panic missing `# Panics` section", - panic_span, + panic_info.map(|el| el.0), "first possible panic found here", ); } diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 7fdb582e640..9f08973948a 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1,13 +1,14 @@ +mod lazy_continuation; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; -use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args}; +use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, }; -use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph}; +use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; @@ -362,6 +363,63 @@ declare_clippy_lint! { "docstrings exist but documentation is empty" } +declare_clippy_lint! { + /// ### What it does + /// + /// In CommonMark Markdown, the language used to write doc comments, a + /// paragraph nested within a list or block quote does not need any line + /// after the first one to be indented or marked. The specification calls + /// this a "lazy paragraph continuation." + /// + /// ### Why is this bad? + /// + /// This is easy to write but hard to read. Lazy continuations makes + /// unintended markers hard to see, and make it harder to deduce the + /// document's intended structure. + /// + /// ### Example + /// + /// This table is probably intended to have two rows, + /// but it does not. It has zero rows, and is followed by + /// a block quote. + /// ```no_run + /// /// Range | Description + /// /// ----- | ----------- + /// /// >= 1 | fully opaque + /// /// < 1 | partially see-through + /// fn set_opacity(opacity: f32) {} + /// ``` + /// + /// Fix it by escaping the marker: + /// ```no_run + /// /// Range | Description + /// /// ----- | ----------- + /// /// \>= 1 | fully opaque + /// /// < 1 | partially see-through + /// fn set_opacity(opacity: f32) {} + /// ``` + /// + /// This example is actually intended to be a list: + /// ```no_run + /// /// * Do nothing. + /// /// * Then do something. Whatever it is needs done, + /// /// it should be done right now. + /// # fn do_stuff() {} + /// ``` + /// + /// Fix it by indenting the list contents: + /// ```no_run + /// /// * Do nothing. + /// /// * Then do something. Whatever it is needs done, + /// /// it should be done right now. + /// # fn do_stuff() {} + /// ``` + #[clippy::version = "1.80.0"] + pub DOC_LAZY_CONTINUATION, + style, + "require every line of a paragraph to be indented and marked" +} + #[derive(Clone)] pub struct Documentation { valid_idents: FxHashSet<String>, @@ -388,6 +446,7 @@ impl_lint_pass!(Documentation => [ UNNECESSARY_SAFETY_DOC, SUSPICIOUS_DOC_COMMENTS, EMPTY_DOCS, + DOC_LAZY_CONTINUATION, ]); impl<'tcx> LateLintPass<'tcx> for Documentation { @@ -402,14 +461,14 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { let body = cx.tcx.hir().body(body_id); - let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); missing_headers::check( cx, item.owner_id, sig, headers, Some(body_id), - panic_span, + panic_info, self.check_private_items, ); } @@ -551,6 +610,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ cx, valid_idents, parser.into_offset_iter(), + &doc, Fragments { fragments: &fragments, doc: &doc, @@ -560,6 +620,11 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"]; +enum Container { + Blockquote, + List(usize), +} + /// Checks parsed documentation. /// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`, /// so lints here will generally access that information. @@ -569,6 +634,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, events: Events, + doc: &str, fragments: Fragments<'_>, ) -> DocHeaders { // true if a safety header was found @@ -576,6 +642,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize let mut in_code = false; let mut in_link = None; let mut in_heading = false; + let mut in_footnote_definition = false; let mut is_rust = false; let mut no_test = false; let mut ignore = false; @@ -586,7 +653,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize let mut code_level = 0; let mut blockquote_level = 0; - for (event, range) in events { + let mut containers = Vec::new(); + + let mut events = events.peekable(); + + while let Some((event, range)) = events.next() { match event { Html(tag) => { if tag.starts_with("<code") { @@ -599,8 +670,14 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize blockquote_level -= 1; } }, - Start(BlockQuote) => blockquote_level += 1, - End(BlockQuote) => blockquote_level -= 1, + Start(BlockQuote) => { + blockquote_level += 1; + containers.push(Container::Blockquote); + }, + End(BlockQuote) => { + blockquote_level -= 1; + containers.pop(); + }, Start(CodeBlock(ref kind)) => { in_code = true; if let CodeBlockKind::Fenced(lang) = kind { @@ -633,6 +710,13 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize if let Start(Heading(_, _, _)) = event { in_heading = true; } + if let Start(Item) = event { + if let Some((_next_event, next_range)) = events.peek() { + containers.push(Container::List(next_range.start - range.start)); + } else { + containers.push(Container::List(0)); + } + } ticks_unbalanced = false; paragraph_range = range; }, @@ -640,6 +724,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize if let End(Heading(_, _, _)) = event { in_heading = false; } + if let End(Item) = event { + containers.pop(); + } if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { span_lint_and_help( cx, @@ -658,8 +745,27 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize } text_to_check = Vec::new(); }, + Start(FootnoteDefinition(..)) => in_footnote_definition = true, + End(FootnoteDefinition(..)) => in_footnote_definition = false, Start(_tag) | End(_tag) => (), // We don't care about other tags - SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (), + SoftBreak | HardBreak => { + if !containers.is_empty() + && let Some((next_event, next_range)) = events.peek() + && let Some(next_span) = fragments.span(cx, next_range.clone()) + && let Some(span) = fragments.span(cx, range.clone()) + && !in_footnote_definition + && !matches!(next_event, End(_)) + { + lazy_continuation::check( + cx, + doc, + range.end..next_range.start, + Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()), + &containers[..], + ); + } + }, + TaskListMarker(_) | Code(_) | Rule => (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; ticks_unbalanced |= text.contains('`') && !in_code; @@ -701,6 +807,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize struct FindPanicUnwrap<'a, 'tcx> { cx: &'a LateContext<'tcx>, + is_const: bool, panic_span: Option<Span>, typeck_results: &'tcx ty::TypeckResults<'tcx>, } @@ -710,14 +817,15 @@ impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> { cx: &'a LateContext<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, body: impl Visitable<'tcx>, - ) -> Option<Span> { + ) -> Option<(Span, bool)> { let mut vis = Self { cx, + is_const: false, panic_span: None, typeck_results, }; body.visit(&mut vis); - vis.panic_span + vis.panic_span.map(|el| (el, vis.is_const)) } } @@ -736,6 +844,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { "assert" | "assert_eq" | "assert_ne" ) { + self.is_const = in_constant(self.cx, expr.hir_id); self.panic_span = Some(macro_call.span); } } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 6715de52649..8d6e27700d8 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -104,7 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { too_large_for_stack: self.too_large_for_stack, }; - ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v).consume_body(body).into_ok(); + ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v) + .consume_body(body) + .into_ok(); for node in v.set { span_lint_hir( diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 724e1843359..3c4a043a732 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_args, format_args_inputs_span}; +use clippy_utils::macros::{format_args_inputs_span, FormatArgsStorage}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::{sym, ExpnId}; declare_clippy_lint! { @@ -38,7 +38,17 @@ declare_clippy_lint! { "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work" } -declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]); +pub struct ExplicitWrite { + format_args: FormatArgsStorage, +} + +impl ExplicitWrite { + pub fn new(format_args: FormatArgsStorage) -> Self { + Self { format_args } + } +} + +impl_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]); impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -57,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { Some(sym::io_stderr) => ("stderr", "e"), _ => return, }; - let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { + let Some(format_args) = self.format_args.get(cx, write_arg, ExpnId::root()) else { return; }; @@ -83,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { }; let mut applicability = Applicability::MachineApplicable; let inputs_snippet = - snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability); + snippet_with_applicability(cx, format_args_inputs_span(format_args), "..", &mut applicability); span_lint_and_sugg( cx, EXPLICIT_WRITE, diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index 8a0cd155d21..0b248f784b7 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node}; +use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -39,13 +39,24 @@ declare_clippy_lint! { "useless use of `format!`" } -declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); +#[allow(clippy::module_name_repetitions)] +pub struct UselessFormat { + format_args: FormatArgsStorage, +} + +impl UselessFormat { + pub fn new(format_args: FormatArgsStorage) -> Self { + Self { format_args } + } +} + +impl_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(cx, expr) && cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) - && let Some(format_args) = find_format_args(cx, expr, macro_call.expn) + && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { let mut applicability = Applicability::MachineApplicable; let call_site = macro_call.span; diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 003a9995c15..86115807aa4 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -3,8 +3,8 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ - find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, - is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, + find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, + is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, }; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -167,15 +167,18 @@ impl_lint_pass!(FormatArgs => [ UNUSED_FORMAT_SPECS, ]); +#[allow(clippy::struct_field_names)] pub struct FormatArgs { + format_args: FormatArgsStorage, msrv: Msrv, ignore_mixed: bool, } impl FormatArgs { #[must_use] - pub fn new(msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self { + pub fn new(format_args: FormatArgsStorage, msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self { Self { + format_args, msrv, ignore_mixed: allow_mixed_uninlined_format_args, } @@ -186,13 +189,13 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some(macro_call) = root_macro_call_first_node(cx, expr) && is_format_macro(cx, macro_call.def_id) - && let Some(format_args) = find_format_args(cx, expr, macro_call.expn) + && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { let linter = FormatArgsExpr { cx, expr, macro_call: ¯o_call, - format_args: &format_args, + format_args, ignore_mixed: self.ignore_mixed, }; diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 0a52347940a..09be7237b5c 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node}; +use clippy_utils::macros::{find_format_arg_expr, is_format_macro, root_macro_call_first_node, FormatArgsStorage}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; @@ -99,13 +99,15 @@ struct FormatTraitNames { #[derive(Default)] pub struct FormatImpl { + format_args: FormatArgsStorage, // Whether we are inside Display or Debug trait impl - None for neither format_trait_impl: Option<FormatTraitNames>, } impl FormatImpl { - pub fn new() -> Self { + pub fn new(format_args: FormatArgsStorage) -> Self { Self { + format_args, format_trait_impl: None, } } @@ -129,6 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { if let Some(format_trait_impl) = self.format_trait_impl { let linter = FormatImplExpr { cx, + format_args: &self.format_args, expr, format_trait_impl, }; @@ -141,6 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { struct FormatImplExpr<'a, 'tcx> { cx: &'a LateContext<'tcx>, + format_args: &'a FormatArgsStorage, expr: &'tcx Expr<'tcx>, format_trait_impl: FormatTraitNames, } @@ -175,7 +179,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { if let Some(outer_macro) = root_macro_call_first_node(self.cx, self.expr) && let macro_def_id = outer_macro.def_id && is_format_macro(self.cx, macro_def_id) - && let Some(format_args) = find_format_args(self.cx, self.expr, outer_macro.expn) + && let Some(format_args) = self.format_args.get(self.cx, self.expr, outer_macro.expn) { for piece in &format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index 633ed96d6a6..82ce501bac5 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_integer_literal; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::{in_constant, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -47,6 +47,9 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind && let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind + // do not lint in constant context, because the suggestion won't work. + // NB: keep this check until a new `const_trait_impl` is available and stablized. + && !in_constant(cx, exp.hir_id) // check if the first part of the path is some integer primitive && let TyKind::Path(ty_qpath) = &ty.kind diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 9cc51fa8cd5..dfcaac9abef 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -2,15 +2,17 @@ mod impl_trait_in_params; mod misnamed_getters; mod must_use; mod not_unsafe_ptr_arg_deref; +mod renamed_function_params; mod result; mod too_many_arguments; mod too_many_lines; +use clippy_utils::def_path_def_ids; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::{DefIdSet, LocalDefId}; use rustc_span::Span; declare_clippy_lint! { @@ -359,13 +361,51 @@ declare_clippy_lint! { "`impl Trait` is used in the function's parameters" } -#[derive(Copy, Clone)] -#[allow(clippy::struct_field_names)] +declare_clippy_lint! { + /// ### What it does + /// Lints when the name of function parameters from trait impl is + /// different than its default implementation. + /// + /// ### Why is this bad? + /// Using the default name for parameters of a trait method is often + /// more desirable for consistency's sake. + /// + /// ### Example + /// ```rust + /// struct A(u32); + /// + /// impl PartialEq for A { + /// fn eq(&self, b: &Self) -> bool { + /// self.0 == b.0 + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct A(u32); + /// + /// impl PartialEq for A { + /// fn eq(&self, other: &Self) -> bool { + /// self.0 == other.0 + /// } + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub RENAMED_FUNCTION_PARAMS, + restriction, + "renamed function parameters in trait implementation" +} + +#[derive(Clone)] pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64, avoid_breaking_exported_api: bool, + allow_renamed_params_for: Vec<String>, + /// A set of resolved `def_id` of traits that are configured to allow + /// function params renaming. + trait_ids: DefIdSet, } impl Functions { @@ -374,12 +414,15 @@ impl Functions { too_many_lines_threshold: u64, large_error_threshold: u64, avoid_breaking_exported_api: bool, + allow_renamed_params_for: Vec<String>, ) -> Self { Self { too_many_arguments_threshold, too_many_lines_threshold, large_error_threshold, avoid_breaking_exported_api, + allow_renamed_params_for, + trait_ids: DefIdSet::default(), } } } @@ -395,6 +438,7 @@ impl_lint_pass!(Functions => [ RESULT_LARGE_ERR, MISNAMED_GETTERS, IMPL_TRAIT_IN_PARAMS, + RENAMED_FUNCTION_PARAMS, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -424,6 +468,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { must_use::check_impl_item(cx, item); result::check_impl_item(cx, item, self.large_error_threshold); impl_trait_in_params::check_impl_item(cx, item); + renamed_function_params::check_impl_item(cx, item, &self.trait_ids); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { @@ -433,4 +478,12 @@ impl<'tcx> LateLintPass<'tcx> for Functions { result::check_trait_item(cx, item, self.large_error_threshold); impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); } + + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + for path in &self.allow_renamed_params_for { + let path_segments: Vec<&str> = path.split("::").collect(); + let ids = def_path_def_ids(cx, &path_segments); + self.trait_ids.extend(ids); + } + } } diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs new file mode 100644 index 00000000000..c7de0385c02 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -0,0 +1,110 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::{Applicability, MultiSpan}; +use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_hir::hir_id::OwnerId; +use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef}; +use rustc_lint::LateContext; +use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::Span; + +use super::RENAMED_FUNCTION_PARAMS; + +pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored_traits: &DefIdSet) { + if !item.span.from_expansion() + && let ImplItemKind::Fn(_, body_id) = item.kind + && let parent_node = cx.tcx.parent_hir_node(item.hir_id()) + && let Node::Item(parent_item) = parent_node + && let ItemKind::Impl(Impl { + items, + of_trait: Some(trait_ref), + .. + }) = &parent_item.kind + && let Some(did) = trait_item_def_id_of_impl(items, item.owner_id) + && !is_from_ignored_trait(trait_ref, ignored_traits) + { + let mut param_idents_iter = cx.tcx.hir().body_param_names(body_id); + let mut default_param_idents_iter = cx.tcx.fn_arg_names(did).iter().copied(); + + let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter); + if !renames.0.is_empty() { + let multi_span = renames.multi_span(); + let plural = if renames.0.len() == 1 { "" } else { "s" }; + span_lint_and_then( + cx, + RENAMED_FUNCTION_PARAMS, + multi_span, + format!("renamed function parameter{plural} of trait impl"), + |diag| { + diag.multipart_suggestion( + format!("consider using the default name{plural}"), + renames.0, + Applicability::Unspecified, + ); + }, + ); + } + } +} + +struct RenamedFnArgs(Vec<(Span, String)>); + +impl RenamedFnArgs { + /// Comparing between an iterator of default names and one with current names, + /// then collect the ones that got renamed. + fn new<I, T>(default_names: &mut I, current_names: &mut T) -> Self + where + I: Iterator<Item = Ident>, + T: Iterator<Item = Ident>, + { + let mut renamed: Vec<(Span, String)> = vec![]; + + debug_assert!(default_names.size_hint() == current_names.size_hint()); + while let (Some(def_name), Some(cur_name)) = (default_names.next(), current_names.next()) { + let current_name = cur_name.name; + let default_name = def_name.name; + if is_unused_or_empty_symbol(current_name) || is_unused_or_empty_symbol(default_name) { + continue; + } + if current_name != default_name { + renamed.push((cur_name.span, default_name.to_string())); + } + } + + Self(renamed) + } + + fn multi_span(&self) -> MultiSpan { + self.0 + .iter() + .map(|(span, _)| span) + .copied() + .collect::<Vec<Span>>() + .into() + } +} + +fn is_unused_or_empty_symbol(symbol: Symbol) -> bool { + // FIXME: `body_param_names` currently returning empty symbols for `wild` as well, + // so we need to check if the symbol is empty first. + // Therefore the check of whether it's equal to [`kw::Underscore`] has no use for now, + // but it would be nice to keep it here just to be future-proof. + symbol.is_empty() || symbol == kw::Underscore || symbol.as_str().starts_with('_') +} + +/// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item. +fn trait_item_def_id_of_impl(items: &[ImplItemRef], target: OwnerId) -> Option<DefId> { + items.iter().find_map(|item| { + if item.id.owner_id == target { + item.trait_item_def_id + } else { + None + } + }) +} + +fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool { + let Some(trait_did) = of_trait.trait_def_id() else { + return false; + }; + ignored_traits.contains(&trait_did) +} diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 2c2daac0234..192fb611c2d 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -4,8 +4,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_middle::ty::print::PrintTraitRefExt; +use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index a8bfbbdd9ec..3328d642bd8 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -61,11 +61,6 @@ extern crate clippy_utils; #[macro_use] extern crate declare_clippy_lint; -use std::collections::BTreeMap; - -use rustc_data_structures::fx::FxHashSet; -use rustc_lint::{Lint, LintId}; - #[cfg(feature = "internal")] pub mod deprecated_lints; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] @@ -199,6 +194,7 @@ mod lifetimes; mod lines_filter_map_ok; mod literal_representation; mod loops; +mod macro_metavars_in_unsafe; mod macro_use; mod main_recursion; mod manual_assert; @@ -385,6 +381,10 @@ mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` use clippy_config::{get_configuration_metadata, Conf}; +use clippy_utils::macros::FormatArgsStorage; +use rustc_data_structures::fx::FxHashSet; +use rustc_lint::{Lint, LintId}; +use std::collections::BTreeMap; /// Register all pre expansion lints /// @@ -533,6 +533,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_expect_in_tests, allow_mixed_uninlined_format_args, allow_one_hash_in_raw_strings, + allow_panic_in_tests, allow_print_in_tests, allow_private_module_inception, allow_unwrap_in_tests, @@ -597,9 +598,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { ref allowed_duplicate_crates, allow_comparison_to_zero, ref allowed_prefixes, + ref allow_renamed_params_for, blacklisted_names: _, cyclomatic_complexity_threshold: _, + warn_unsafe_macro_metavars_in_private_macros, } = *conf; let msrv = || msrv.clone(); @@ -616,6 +619,14 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { } } + let format_args_storage = FormatArgsStorage::default(); + let format_args = format_args_storage.clone(); + store.register_early_pass(move || { + Box::new(utils::format_args_collector::FormatArgsCollector::new( + format_args.clone(), + )) + }); + // all the internal lints #[cfg(feature = "internal")] { @@ -656,7 +667,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { .collect(), )) }); - store.register_early_pass(|| Box::<utils::format_args_collector::FormatArgsCollector>::default()); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); store.register_late_pass(move |_| { @@ -698,6 +708,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv()))); + let format_args = format_args_storage.clone(); store.register_late_pass(move |_| { Box::new(methods::Methods::new( avoid_breaking_exported_api, @@ -705,6 +716,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_expect_in_tests, allow_unwrap_in_tests, allowed_dotfiles.clone(), + format_args.clone(), )) }); store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv()))); @@ -759,7 +771,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_in_test: allow_useless_vec_in_tests, }) }); - store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); + store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented { allow_panic_in_tests })); store.register_late_pass(|_| Box::new(strings::StringLitAsBytes)); store.register_late_pass(|_| Box::new(derive::Derive)); store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv()))); @@ -769,7 +781,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::<regex::Regex>::default()); store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); - store.register_late_pass(|_| Box::new(format::UselessFormat)); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone()))); store.register_late_pass(|_| Box::new(swap::Swap)); store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default()); @@ -780,6 +793,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { too_many_lines_threshold, large_error_threshold, avoid_breaking_exported_api, + allow_renamed_params_for.clone(), )) }); store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items))); @@ -793,7 +807,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl)); store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount)); store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold))); - store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite)); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(explicit_write::ExplicitWrite::new(format_args.clone()))); store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue)); store.register_late_pass(move |tcx| { Box::new(pass_by_ref_or_value::PassByRefOrValue::new( @@ -835,7 +850,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone()))); store.register_early_pass(|| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); - store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new())); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone()))); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); @@ -961,8 +977,14 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { accept_comment_above_attributes, )) }); - store - .register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined_format_args))); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| { + Box::new(format_args::FormatArgs::new( + format_args.clone(), + msrv(), + allow_mixed_uninlined_format_args, + )) + }); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); @@ -973,7 +995,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default()); store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); - store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests))); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(write::Write::new(format_args.clone(), allow_print_in_tests))); store.register_late_pass(move |_| { Box::new(cargo::Cargo { ignore_publish: cargo_ignore_publish, @@ -1136,6 +1159,12 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects)); store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault)); store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed)); + store.register_late_pass(move |_| { + Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe { + warn_unsafe_macro_metavars_in_private_macros, + ..Default::default() + }) + }); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index b5e39b33c6a..3dcb050d77e 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -17,6 +17,7 @@ mod same_item_push; mod single_element_loop; mod unused_enumerate_index; mod utils; +mod while_float; mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; @@ -418,6 +419,39 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for while loops comparing floating point values. + /// + /// ### Why is this bad? + /// If you increment floating point values, errors can compound, + /// so, use integers instead if possible. + /// + /// ### Known problems + /// The lint will catch all while loops comparing floating point + /// values without regarding the increment. + /// + /// ### Example + /// ```no_run + /// let mut x = 0.0; + /// while x < 42.0 { + /// x += 1.0; + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// let mut x = 0; + /// while x < 42 { + /// x += 1; + /// } + /// ``` + #[clippy::version = "1.80.0"] + pub WHILE_FLOAT, + nursery, + "while loops comaparing floating point values" +} + +declare_clippy_lint! { + /// ### What it does /// Checks whether a for loop is being used to push a constant /// value into a Vec. /// @@ -706,6 +740,7 @@ impl_lint_pass!(Loops => [ NEVER_LOOP, MUT_RANGE_BOUND, WHILE_IMMUTABLE_CONDITION, + WHILE_FLOAT, SAME_ITEM_PUSH, SINGLE_ELEMENT_LOOP, MISSING_SPIN_LOOP, @@ -762,6 +797,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) { while_immutable_condition::check(cx, condition, body); + while_float::check(cx, condition); missing_spin_loop::check(cx, condition, body); manual_while_let_some::check(cx, condition, body, span); } diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 6b9ecf5f141..6c6a9a1a2e0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -60,12 +60,9 @@ fn check_for_mutation( span_low: None, span_high: None, }; - ExprUseVisitor::for_clippy( - cx, - body.hir_id.owner.def_id, - &mut delegate, - ) - .walk_expr(body).into_ok(); + ExprUseVisitor::for_clippy(cx, body.hir_id.owner.def_id, &mut delegate) + .walk_expr(body) + .into_ok(); delegate.mutation_span() } diff --git a/src/tools/clippy/clippy_lints/src/loops/while_float.rs b/src/tools/clippy/clippy_lints/src/loops/while_float.rs new file mode 100644 index 00000000000..cf62ce29f0c --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/loops/while_float.rs @@ -0,0 +1,20 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_hir::ExprKind; + +pub(super) fn check(cx: &rustc_lint::LateContext<'_>, condition: &rustc_hir::Expr<'_>) { + if let ExprKind::Binary(_op, left, right) = condition.kind + && is_float_type(cx, left) + && is_float_type(cx, right) + { + span_lint( + cx, + super::WHILE_FLOAT, + condition.span, + "while condition comparing floats", + ); + } +} + +fn is_float_type(cx: &rustc_lint::LateContext<'_>, expr: &rustc_hir::Expr<'_>) -> bool { + cx.typeck_results().expr_ty(expr).is_floating_point() +} diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs new file mode 100644 index 00000000000..aea3d26e187 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -0,0 +1,256 @@ +use std::collections::btree_map::Entry; +use std::collections::BTreeMap; + +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::is_lint_allowed; +use itertools::Itertools; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; +use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::impl_lint_pass; +use rustc_span::{sym, Span, SyntaxContext}; + +declare_clippy_lint! { + /// ### What it does + /// Looks for macros that expand metavariables in an unsafe block. + /// + /// ### Why is this bad? + /// This hides an unsafe block and allows the user of the macro to write unsafe code without an explicit + /// unsafe block at callsite, making it possible to perform unsafe operations in seemingly safe code. + /// + /// The macro should be restructured so that these metavariables are referenced outside of unsafe blocks + /// and that the usual unsafety checks apply to the macro argument. + /// + /// This is usually done by binding it to a variable outside of the unsafe block + /// and then using that variable inside of the block as shown in the example, or by referencing it a second time + /// in a safe context, e.g. `if false { $expr }`. + /// + /// ### Known limitations + /// Due to how macros are represented in the compiler at the time Clippy runs its lints, + /// it's not possible to look for metavariables in macro definitions directly. + /// + /// Instead, this lint looks at expansions of macros. + /// This leads to false negatives for macros that are never actually invoked. + /// + /// By default, this lint is rather conservative and will only emit warnings on publicly-exported + /// macros from the same crate, because oftentimes private internal macros are one-off macros where + /// this lint would just be noise (e.g. macros that generate `impl` blocks). + /// The default behavior should help with preventing a high number of such false positives, + /// however it can be configured to also emit warnings in private macros if desired. + /// + /// ### Example + /// ```no_run + /// /// Gets the first element of a slice + /// macro_rules! first { + /// ($slice:expr) => { + /// unsafe { + /// let slice = $slice; // ⚠️ expansion inside of `unsafe {}` + /// + /// assert!(!slice.is_empty()); + /// // SAFETY: slice is checked to have at least one element + /// slice.first().unwrap_unchecked() + /// } + /// } + /// } + /// + /// assert_eq!(*first!(&[1i32]), 1); + /// + /// // This will compile as a consequence (note the lack of `unsafe {}`) + /// assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1); + /// ``` + /// Use instead: + /// ```compile_fail + /// macro_rules! first { + /// ($slice:expr) => {{ + /// let slice = $slice; // ✅ outside of `unsafe {}` + /// unsafe { + /// assert!(!slice.is_empty()); + /// // SAFETY: slice is checked to have at least one element + /// slice.first().unwrap_unchecked() + /// } + /// }} + /// } + /// + /// assert_eq!(*first!(&[1]), 1); + /// + /// // This won't compile: + /// assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1); + /// ``` + #[clippy::version = "1.80.0"] + pub MACRO_METAVARS_IN_UNSAFE, + suspicious, + "expanding macro metavariables in an unsafe block" +} +impl_lint_pass!(ExprMetavarsInUnsafe => [MACRO_METAVARS_IN_UNSAFE]); + +#[derive(Clone, Debug)] +pub enum MetavarState { + ReferencedInUnsafe { unsafe_blocks: Vec<HirId> }, + ReferencedInSafe, +} + +#[derive(Default)] +pub struct ExprMetavarsInUnsafe { + pub warn_unsafe_macro_metavars_in_private_macros: bool, + /// A metavariable can be expanded more than once, potentially across multiple bodies, so it + /// requires some state kept across HIR nodes to make it possible to delay a warning + /// and later undo: + /// + /// ```ignore + /// macro_rules! x { + /// ($v:expr) => { + /// unsafe { $v; } // unsafe context, it might be possible to emit a warning here, so add it to the map + /// + /// $v; // `$v` expanded another time but in a safe context, set to ReferencedInSafe to suppress + /// } + /// } + /// ``` + pub metavar_expns: BTreeMap<Span, MetavarState>, +} + +struct BodyVisitor<'a, 'tcx> { + /// Stack of unsafe blocks -- the top item always represents the last seen unsafe block from + /// within a relevant macro. + macro_unsafe_blocks: Vec<HirId>, + /// When this is >0, it means that the node currently being visited is "within" a + /// macro definition. This is not necessary for correctness, it merely helps reduce the number + /// of spans we need to insert into the map, since only spans from macros are relevant. + expn_depth: u32, + cx: &'a LateContext<'tcx>, + lint: &'a mut ExprMetavarsInUnsafe, +} + +fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + (cx.effective_visibilities.is_exported(def_id) || cx.tcx.has_attr(def_id, sym::macro_export)) + && !cx.tcx.is_doc_hidden(def_id) +} + +impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> { + fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) { + let from_expn = s.span.from_expansion(); + if from_expn { + self.expn_depth += 1; + } + walk_stmt(self, s); + if from_expn { + self.expn_depth -= 1; + } + } + + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + let ctxt = e.span.ctxt(); + + if let ExprKind::Block(block, _) = e.kind + && let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules + && !ctxt.is_root() + && let Some(macro_def_id) = ctxt.outer_expn_data().macro_def_id + && let Some(macro_def_id) = macro_def_id.as_local() + && (self.lint.warn_unsafe_macro_metavars_in_private_macros || is_public_macro(self.cx, macro_def_id)) + { + self.macro_unsafe_blocks.push(block.hir_id); + walk_block(self, block); + self.macro_unsafe_blocks.pop(); + } else if ctxt.is_root() && self.expn_depth > 0 { + let unsafe_block = self.macro_unsafe_blocks.last().copied(); + + match (self.lint.metavar_expns.entry(e.span), unsafe_block) { + (Entry::Vacant(e), None) => { + e.insert(MetavarState::ReferencedInSafe); + }, + (Entry::Vacant(e), Some(unsafe_block)) => { + e.insert(MetavarState::ReferencedInUnsafe { + unsafe_blocks: vec![unsafe_block], + }); + }, + (Entry::Occupied(mut e), None) => { + if let MetavarState::ReferencedInUnsafe { .. } = *e.get() { + e.insert(MetavarState::ReferencedInSafe); + } + }, + (Entry::Occupied(mut e), Some(unsafe_block)) => { + if let MetavarState::ReferencedInUnsafe { unsafe_blocks } = e.get_mut() + && !unsafe_blocks.contains(&unsafe_block) + { + unsafe_blocks.push(unsafe_block); + } + }, + } + + // NB: No need to visit descendant nodes. They're guaranteed to represent the same + // metavariable + } else { + walk_expr(self, e); + } + } +} + +impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx rustc_hir::Body<'tcx>) { + if is_lint_allowed(cx, MACRO_METAVARS_IN_UNSAFE, body.value.hir_id) { + return; + } + + // This BodyVisitor is separate and not part of the lint pass because there is no + // `check_stmt_post` on `(Late)LintPass`, which we'd need to detect when we're leaving a macro span + + let mut vis = BodyVisitor { + #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning + expn_depth: if body.value.span.from_expansion() { 1 } else { 0 }, + macro_unsafe_blocks: Vec::new(), + lint: self, + cx + }; + vis.visit_body(body); + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + // Aggregate all unsafe blocks from all spans: + // ``` + // macro_rules! x { + // ($w:expr, $x:expr, $y:expr) => { $w; unsafe { $w; $x; }; unsafe { $x; $y; }; } + // } + // $w: [] (unsafe#0 is never added because it was referenced in a safe context) + // $x: [unsafe#0, unsafe#1] + // $y: [unsafe#1] + // ``` + // We want to lint unsafe blocks #0 and #1 + let bad_unsafe_blocks = self + .metavar_expns + .iter() + .filter_map(|(_, state)| match state { + MetavarState::ReferencedInUnsafe { unsafe_blocks } => Some(unsafe_blocks.as_slice()), + MetavarState::ReferencedInSafe => None, + }) + .flatten() + .copied() + .map(|id| { + // Remove the syntax context to hide "in this macro invocation" in the diagnostic. + // The invocation doesn't matter. Also we want to dedupe by the unsafe block and not by anything + // related to the callsite. + let span = cx.tcx.hir().span(id); + + (id, Span::new(span.lo(), span.hi(), SyntaxContext::root(), None)) + }) + .dedup_by(|&(_, a), &(_, b)| a == b); + + for (id, span) in bad_unsafe_blocks { + span_lint_hir_and_then( + cx, + MACRO_METAVARS_IN_UNSAFE, + id, + span, + "this macro expands metavariables in an unsafe block", + |diag| { + diag.note("this allows the user of the macro to write unsafe code outside of an unsafe block"); + diag.help( + "consider expanding any metavariables outside of this block, e.g. by storing them in a variable", + ); + diag.help( + "... or also expand referenced metavariables in a safe context to require an unsafe block at callsite", + ); + }, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 1eadc200bed..e2ab4415518 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -611,15 +611,22 @@ impl<'tcx> BinaryOp<'tcx> { /// The clamp meta pattern is a pattern shared between many (but not all) patterns. /// In summary, this pattern consists of two if statements that meet many criteria, +/// /// - binary operators that are one of [`>`, `<`, `>=`, `<=`]. +/// /// - Both binary statements must have a shared argument +/// /// - Which can appear on the left or right side of either statement +/// /// - The binary operators must define a finite range for the shared argument. To put this in /// the terms of Rust `std` library, the following ranges are acceptable +/// /// - `Range` /// - `RangeInclusive` +/// /// And all other range types are not accepted. For the purposes of `clamp` it's irrelevant /// whether the range is inclusive or not, the output is the same. +/// /// - The result of each if statement must be equal to the argument unique to that if statement. The /// result can not be the shared argument in either case. fn is_clamp_meta_pattern<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index cd61e733694..da8c918a62b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; use core::cmp::Ordering; use core::{iter, slice}; @@ -9,9 +9,9 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; -use rustc_span::{ErrorGuaranteed, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; use super::MATCH_SAME_ARMS; @@ -110,20 +110,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { && check_same_body() }; + let mut appl = Applicability::MaybeIncorrect; let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) { if matches!(arm2.pat.kind, PatKind::Wild) { if !cx.tcx.features().non_exhaustive_omitted_patterns_lint || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) { + let arm_span = adjusted_arm_span(cx, arm1.span); span_lint_hir_and_then( cx, MATCH_SAME_ARMS, arm1.hir_id, - arm1.span, + arm_span, "this match arm has an identical body to the `_` wildcard arm", |diag| { - diag.span_suggestion(arm1.span, "try removing the arm", "", Applicability::MaybeIncorrect) + diag.span_suggestion(arm_span, "try removing the arm", "", appl) .help("or try changing either arm body") .span_note(arm2.span, "`_` wildcard arm here"); }, @@ -144,23 +146,36 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { keep_arm.span, "this match arm has an identical body to another arm", |diag| { - let move_pat_snip = snippet(cx, move_arm.pat.span, "<pat2>"); - let keep_pat_snip = snippet(cx, keep_arm.pat.span, "<pat1>"); + let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "<pat2>", &mut appl); + let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "<pat1>", &mut appl); diag.span_suggestion( keep_arm.pat.span, - "try merging the arm patterns", + "or try merging the arm patterns", format!("{keep_pat_snip} | {move_pat_snip}"), - Applicability::MaybeIncorrect, + appl, ) - .help("or try changing either arm body") - .span_note(move_arm.span, "other arm here"); + .span_suggestion( + adjusted_arm_span(cx, move_arm.span), + "and remove this obsolete arm", + "", + appl, + ) + .help("try changing either arm body"); }, ); } } } +/// Extend arm's span to include the comma and whitespaces after it. +fn adjusted_arm_span(cx: &LateContext<'_>, span: Span) -> Span { + let source_map = cx.sess().source_map(); + source_map + .span_extend_while(span, |c| c == ',' || c.is_ascii_whitespace()) + .unwrap_or(span) +} + #[derive(Clone, Copy)] enum NormalizedPat<'a> { Wild, diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index f775ea072e1..6ac0705abb2 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -115,45 +115,60 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { } } - fn get_type(&self, ex: &'tcx Expr<'_>) -> Ty<'tcx> { - self.cx.typeck_results().expr_ty(ex) + fn is_sig_drop_expr(&mut self, ex: &'tcx Expr<'_>) -> bool { + !ex.is_syntactic_place_expr() && self.has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex)) } - fn has_seen_type(&mut self, ty: Ty<'tcx>) -> bool { - !self.seen_types.insert(ty) + fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + self.seen_types.clear(); + self.has_sig_drop_attr_impl(ty) } - fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + fn has_sig_drop_attr_impl(&mut self, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { - if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 { + if get_attr( + self.cx.sess(), + self.cx.tcx.get_attrs_unchecked(adt.did()), + "has_significant_drop", + ) + .count() + > 0 + { return true; } } - match ty.kind() { - rustc_middle::ty::Adt(a, b) => { - for f in a.all_fields() { - let ty = f.ty(cx.tcx, b); - if !self.has_seen_type(ty) && self.has_sig_drop_attr(cx, ty) { - return true; - } - } + if !self.seen_types.insert(ty) { + return false; + } - for generic_arg in *b { - if let GenericArgKind::Type(ty) = generic_arg.unpack() { - if self.has_sig_drop_attr(cx, ty) { - return true; - } - } - } - false + let result = match ty.kind() { + rustc_middle::ty::Adt(adt, args) => { + // if some field has significant drop, + adt.all_fields() + .map(|field| field.ty(self.cx.tcx, args)) + .any(|ty| self.has_sig_drop_attr_impl(ty)) + // or if there is no generic lifetime and.. + // (to avoid false positive on `Ref<'a, MutexGuard<Foo>>`) + || (args + .iter() + .all(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_))) + // some generic parameter has significant drop + // (to avoid false negative on `Box<MutexGuard<Foo>>`) + && args + .iter() + .filter_map(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => Some(ty), + _ => None, + }) + .any(|ty| self.has_sig_drop_attr_impl(ty))) }, - rustc_middle::ty::Array(ty, _) - | rustc_middle::ty::RawPtr(ty, _) - | rustc_middle::ty::Ref(_, ty, _) - | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty), + rustc_middle::ty::Tuple(tys) => tys.iter().any(|ty| self.has_sig_drop_attr_impl(ty)), + rustc_middle::ty::Array(ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr_impl(*ty), _ => false, - } + }; + + result } } @@ -232,7 +247,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { if self.current_sig_drop.is_some() { return; } - let ty = self.sig_drop_checker.get_type(expr); + let ty = self.cx.typeck_results().expr_ty(expr); if ty.is_ref() { // We checked that the type was ref, so builtin_deref will return Some, // but let's avoid any chance of an ICE. @@ -279,11 +294,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { - if !self.is_chain_end - && self - .sig_drop_checker - .has_sig_drop_attr(self.cx, self.sig_drop_checker.get_type(ex)) - { + if !self.is_chain_end && self.sig_drop_checker.is_sig_drop_expr(ex) { self.has_significant_drop = true; return; } @@ -387,10 +398,7 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<' impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if self - .sig_drop_checker - .has_sig_drop_attr(self.sig_drop_checker.cx, self.sig_drop_checker.get_type(ex)) - { + if self.sig_drop_checker.is_sig_drop_expr(ex) { self.found_sig_drop_spans.insert(ex.span); return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index fba76852344..c9f56e1d980 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node}; +use clippy_utils::macros::{format_args_inputs_span, root_macro_call_first_node, FormatArgsStorage}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; @@ -16,6 +16,7 @@ use super::EXPECT_FUN_CALL; #[allow(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, + format_args_storage: &FormatArgsStorage, expr: &hir::Expr<'_>, method_span: Span, name: &str, @@ -134,9 +135,9 @@ pub(super) fn check<'tcx>( // Special handling for `format!` as arg_root if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) { if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) - && let Some(format_args) = find_format_args(cx, arg_root, macro_call.expn) + && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn) { - let span = format_args_inputs_span(&format_args); + let span = format_args_inputs_span(format_args); let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs index 12647ea1ffc..b93d51eac64 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs @@ -126,15 +126,15 @@ enum FilterType { /// /// How this is done: /// 1. we know that this is invoked in a method call with `filter` as the method name via `mod.rs` -/// 2. we check that we are in a trait method. Therefore we are in an -/// `(x as Iterator).filter({filter_arg})` method call. +/// 2. we check that we are in a trait method. Therefore we are in an `(x as +/// Iterator).filter({filter_arg})` method call. /// 3. we check that the parent expression is not a map. This is because we don't want to lint /// twice, and we already have a specialized lint for that. /// 4. we check that the span of the filter does not contain a comment. /// 5. we get the type of the `Item` in the `Iterator`, and compare against the type of Option and -/// Result. +/// Result. /// 6. we finally check the contents of the filter argument to see if it is a call to `is_some` or -/// `is_ok`. +/// `is_ok`. /// 7. if all of the above are true, then we return the `FilterType` fn expression_type( cx: &LateContext<'_>, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 7c852a3768d..05e77386128 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -12,8 +12,10 @@ use rustc_middle::ty; use rustc_span::{sym, Span}; /// lint use of: +/// /// - `hashmap.iter().map(|(_, v)| v)` /// - `hashmap.into_iter().map(|(_, v)| v)` +/// /// on `HashMaps` and `BTreeMaps` in std pub(super) fn check<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index a52d38790a2..5ccb5243e90 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -69,12 +69,9 @@ pub(super) fn check<'tcx>( used_move: HirIdSet::default(), }; - ExprUseVisitor::for_clippy( - cx, - closure.def_id, - &mut delegate, - ) - .consume_body(body).into_ok(); + ExprUseVisitor::for_clippy(cx, closure.def_id, &mut delegate) + .consume_body(body) + .into_ok(); let mut to_be_discarded = false; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 2b92bff016d..9d67aa23379 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -133,6 +133,7 @@ use bind_instead_of_map::BindInsteadOfMap; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::macros::FormatArgsStorage; use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty}; pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; @@ -4087,12 +4088,14 @@ declare_clippy_lint! { suspicious, "is_empty() called on strings known at compile time" } + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, allowed_dotfiles: FxHashSet<String>, + format_args: FormatArgsStorage, } impl Methods { @@ -4103,6 +4106,7 @@ impl Methods { allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, mut allowed_dotfiles: FxHashSet<String>, + format_args: FormatArgsStorage, ) -> Self { allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string)); @@ -4112,6 +4116,7 @@ impl Methods { allow_expect_in_tests, allow_unwrap_in_tests, allowed_dotfiles, + format_args, } } } @@ -4281,7 +4286,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); - expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + expect_fun_call::check( + cx, + &self.format_args, + expr, + method_span, + method_call.ident.as_str(), + receiver, + args, + ); clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args); clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args); inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 520dcb2d52d..7431dc1cf0b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -3,10 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; -use clippy_utils::{fn_def_id, get_parent_expr}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; +use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; use rustc_span::{sym, Symbol}; @@ -40,6 +42,53 @@ pub fn check_for_loop_iter( && !clone_or_copy_needed && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) { + // Issue 12098 + // https://github.com/rust-lang/rust-clippy/issues/12098 + // if the assignee have `mut borrow` conflict with the iteratee + // the lint should not execute, former didn't consider the mut case + + // check whether `expr` is mutable + fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(hir_id) = path_to_local(expr) + && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) + { + matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..)) + } else { + true + } + } + + fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Expr<'_>) -> bool { + let mut change = false; + if let ExprKind::Block(block, ..) = body.kind { + for_each_expr(block, |e| { + match e.kind { + ExprKind::Assign(assignee, _, _) | ExprKind::AssignOp(_, assignee, _) => { + change |= !can_mut_borrow_both(cx, caller, assignee); + }, + _ => {}, + } + // the return value has no effect but the function need one return value + ControlFlow::<()>::Continue(()) + }); + } + change + } + + if let ExprKind::Call(_, [child, ..]) = expr.kind { + // filter first layer of iterator + let mut child = child; + // get inner real caller requests for clone + while let ExprKind::MethodCall(_, caller, _, _) = child.kind { + child = caller; + } + if is_mutable(cx, child) && is_caller_or_fields_change(cx, body, child) { + // skip lint + return true; + } + }; + + // the lint should not be executed if no violation happens let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind && maybe_iter_method_name.ident.name == sym::iter && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator) diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index c50f24f824a..34d7b9acbe4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -120,6 +120,7 @@ fn pat_bindings(pat: &Pat<'_>) -> Vec<HirId> { /// operations performed on `binding_hir_ids` are: /// * to take non-mutable references to them /// * to use them as non-mutable `&self` in method calls +/// /// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true /// when `CloneOrCopyVisitor` is done visiting. struct CloneOrCopyVisitor<'cx, 'tcx> { diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index ae6cf992ef7..daf166bad90 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; +use clippy_utils::mir::PossibleBorrowerMap; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; @@ -11,7 +11,6 @@ use rustc_hir::{Body, Expr, ExprKind, Mutability, Path, QPath}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::{ self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, ParamTy, ProjectionPredicate, Ty, }; @@ -106,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { } && let count = needless_borrow_count( cx, - &mut self.possible_borrowers, fn_id, cx.typeck_results().node_args(hir_id), i, @@ -155,11 +153,9 @@ fn path_has_args(p: &QPath<'_>) -> bool { /// The following constraints will be checked: /// * The borrowed expression meets all the generic type's constraints. /// * The generic type appears only once in the functions signature. -/// * The borrowed value will not be moved if it is used later in the function. -#[expect(clippy::too_many_arguments)] +/// * The borrowed value is Copy itself OR not a variable (created by a function call) fn needless_borrow_count<'tcx>( cx: &LateContext<'tcx>, - possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, fn_id: DefId, callee_args: ty::GenericArgsRef<'tcx>, arg_index: usize, @@ -234,9 +230,9 @@ fn needless_borrow_count<'tcx>( let referent_ty = cx.typeck_results().expr_ty(referent); - if !is_copy(cx, referent_ty) - && (referent_ty.has_significant_drop(cx.tcx, cx.param_env) - || !referent_used_exactly_once(cx, possible_borrowers, reference)) + if (!is_copy(cx, referent_ty) && !referent_ty.is_ref()) + && let ExprKind::AddrOf(_, _, inner) = reference.kind + && !matches!(inner.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) { return false; } @@ -339,37 +335,6 @@ fn is_mixed_projection_predicate<'tcx>( } } -fn referent_used_exactly_once<'tcx>( - cx: &LateContext<'tcx>, - possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, - reference: &Expr<'tcx>, -) -> bool { - if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id) - && let Some(local) = expr_local(cx.tcx, reference) - && let [location] = *local_assignments(mir, local).as_slice() - && let block_data = &mir.basic_blocks[location.block] - && let Some(statement) = block_data.statements.get(location.statement_index) - && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind - && !place.is_indirect_first_projection() - { - let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id); - if possible_borrowers - .last() - .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id) - { - possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir))); - } - let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1; - // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is - // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of - // itself. See the comment in that method for an explanation as to why. - possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location) - && used_exactly_once(mir, place.local).unwrap_or(false) - } else { - false - } -} - // Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting // projected type that is a type parameter. Returns `false` if replacing the types would have an // effect on the function signature beyond substituting `new_ty` for `param_ty`. @@ -408,7 +373,11 @@ fn replace_types<'tcx>( && let Some(term_ty) = projection_predicate.term.ty() && let ty::Param(term_param_ty) = term_ty.kind() { - let projection = projection_predicate.projection_term.with_self_ty(cx.tcx, new_ty).expect_ty(cx.tcx).to_ty(cx.tcx); + let projection = projection_predicate + .projection_term + .with_self_ty(cx.tcx, new_ty) + .expect_ty(cx.tcx) + .to_ty(cx.tcx); if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) && args[term_param_ty.index as usize] != GenericArg::from(projected_ty) diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 8b4a12bb766..b97cb4579ca 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -178,8 +178,7 @@ impl EarlyLintPass for NeedlessContinue { /// Given an expression, returns true if either of the following is true /// /// - The expression is a `continue` node. -/// - The expression node is a block with the first statement being a -/// `continue`. +/// - The expression node is a block with the first statement being a `continue`. fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool { match else_expr.kind { ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label), diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 6605d1fa51a..5a0ae1a4d6d 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -273,24 +273,16 @@ fn check<'tcx>( msg_span, "unneeded late initialization", |diag| { - diag.tool_only_span_suggestion( - local_stmt.span, - "remove the local", - "", - Applicability::MachineApplicable, - ); - - diag.span_suggestion( - assign.lhs_span, - format!("declare `{binding_name}` here"), - let_snippet, + diag.multipart_suggestion( + format!("move the declaration `{binding_name}` here"), + vec![(local_stmt.span, String::new()), (assign.lhs_span, let_snippet)], Applicability::MachineApplicable, ); }, ); }, ExprKind::If(cond, then_expr, Some(else_expr)) if !contains_let(cond) => { - let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?; + let (applicability, mut suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?; span_lint_and_then( cx, @@ -298,30 +290,26 @@ fn check<'tcx>( local_stmt.span, "unneeded late initialization", |diag| { - diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability); - - diag.span_suggestion_verbose( - usage.stmt.span.shrink_to_lo(), - format!("declare `{binding_name}` here"), - format!("{let_snippet} = "), - applicability, - ); - - diag.multipart_suggestion("remove the assignments from the branches", suggestions, applicability); + suggestions.push((local_stmt.span, String::new())); + suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = "))); if usage.needs_semi { - diag.span_suggestion( - usage.stmt.span.shrink_to_hi(), - "add a semicolon after the `if` expression", - ";", - applicability, - ); + suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned())); } + + diag.multipart_suggestion( + format!( + "move the declaration `{binding_name}` here and remove the assignments from the branches" + ), + suggestions, + applicability, + ); }, ); }, ExprKind::Match(_, arms, MatchSource::Normal) => { - let (applicability, suggestions) = assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?; + let (applicability, mut suggestions) = + assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?; span_lint_and_then( cx, @@ -329,29 +317,18 @@ fn check<'tcx>( local_stmt.span, "unneeded late initialization", |diag| { - diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability); + suggestions.push((local_stmt.span, String::new())); + suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = "))); - diag.span_suggestion_verbose( - usage.stmt.span.shrink_to_lo(), - format!("declare `{binding_name}` here"), - format!("{let_snippet} = "), - applicability, - ); + if usage.needs_semi { + suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned())); + } diag.multipart_suggestion( - "remove the assignments from the `match` arms", + format!("move the declaration `{binding_name}` here and remove the assignments from the `match` arms"), suggestions, applicability, ); - - if usage.needs_semi { - diag.span_suggestion( - usage.stmt.span.shrink_to_hi(), - "add a semicolon after the `match` expression", - ";", - applicability, - ); - } }, ); }, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 9b852f52ea1..da6ed5fb96f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -117,7 +117,9 @@ fn check_closures<'tcx>( .associated_body() .map(|(_, body_id)| hir.body(body_id)) { - euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx).consume_body(body).into_ok(); + euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx) + .consume_body(body) + .into_ok(); } } } @@ -194,7 +196,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { async_closures: FxHashSet::default(), tcx: cx.tcx, }; - euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx).consume_body(body).into_ok(); + euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx) + .consume_body(body) + .into_ok(); let mut checked_closures = FxHashSet::default(); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 0986571d0f2..f2e00cef7e9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -133,7 +133,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { // function body. let MovedVariablesCtxt { moved_vars } = { let mut ctx = MovedVariablesCtxt::default(); - euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx).consume_body(body).into_ok(); + euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx) + .consume_body(body) + .into_ok(); ctx }; diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index f915145e794..87f886b1128 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -94,7 +94,6 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx rustc_hir::Block<'tcx>) { for hir_id in self.local_bindings.pop().unwrap() { - // FIXME(rust/#120456) - is `swap_remove` correct? if let Some(span) = self.underscore_bindings.swap_remove(&hir_id) { span_lint_hir( cx, @@ -109,7 +108,6 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some(def_id) = path_to_local(expr) { - // FIXME(rust/#120456) - is `swap_remove` correct? self.underscore_bindings.swap_remove(&def_id); } } @@ -118,7 +116,11 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { impl NoEffect { fn check_no_effect(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { if let StmtKind::Semi(expr) = stmt.kind { - // move `expr.span.from_expansion()` ahead + // Covered by rustc `path_statements` lint + if matches!(expr.kind, ExprKind::Path(_)) { + return true; + } + if expr.span.from_expansion() { return false; } diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index ef51a9a9a1c..75066c1f0d2 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -1,8 +1,14 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_in_test; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; + +#[derive(Clone)] +pub struct PanicUnimplemented { + pub allow_panic_in_tests: bool, +} declare_clippy_lint! { /// ### What it does @@ -77,7 +83,7 @@ declare_clippy_lint! { "usage of the `unreachable!` macro" } -declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); +impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -85,7 +91,9 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { return; }; if is_panic(cx, macro_call.def_id) { - if cx.tcx.hir().is_inside_const_context(expr.hir_id) { + if cx.tcx.hir().is_inside_const_context(expr.hir_id) + || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) + { return; } diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 87a3c3874d7..292124196ff 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -389,6 +389,10 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind && path.ident.name == sym::to_string && let ty = cx.typeck_results().expr_ty(self_arg) @@ -437,6 +441,10 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind && path.ident.name == sym::to_string && let ty = cx.typeck_results().expr_ty(self_arg) diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 7d824ef2139..3729dfd3e86 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -28,7 +28,7 @@ pub(super) fn check<'tcx>( let int_ty = substs.type_at(0); if from_ty != int_ty { - return false; + return false; } span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 5b2841dcd83..c0d9bcdd259 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -251,11 +251,7 @@ impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> { local_id: unwrap_info.local_id, }; - let vis = ExprUseVisitor::for_clippy( - self.cx, - cond.hir_id.owner.def_id, - &mut delegate, - ); + let vis = ExprUseVisitor::for_clippy(self.cx, cond.hir_id.owner.def_id, &mut delegate); vis.walk_expr(cond).into_ok(); vis.walk_expr(branch).into_ok(); diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs index 58e66c9f9b9..5acfd35fd6a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs @@ -1,4 +1,4 @@ -use clippy_utils::macros::AST_FORMAT_ARGS; +use clippy_utils::macros::FormatArgsStorage; use clippy_utils::source::snippet_opt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; @@ -9,13 +9,20 @@ use rustc_session::impl_lint_pass; use rustc_span::{hygiene, Span}; use std::iter::once; use std::mem; -use std::rc::Rc; -/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call -/// [`clippy_utils::macros::find_format_args`] -#[derive(Default)] +/// Populates [`FormatArgsStorage`] with AST [`FormatArgs`] nodes pub struct FormatArgsCollector { - format_args: FxHashMap<Span, Rc<FormatArgs>>, + format_args: FxHashMap<Span, FormatArgs>, + storage: FormatArgsStorage, +} + +impl FormatArgsCollector { + pub fn new(storage: FormatArgsStorage) -> Self { + Self { + format_args: FxHashMap::default(), + storage, + } + } } impl_lint_pass!(FormatArgsCollector => []); @@ -27,16 +34,12 @@ impl EarlyLintPass for FormatArgsCollector { return; } - self.format_args - .insert(expr.span.with_parent(None), Rc::new((**args).clone())); + self.format_args.insert(expr.span.with_parent(None), (**args).clone()); } } fn check_crate_post(&mut self, _: &EarlyContext<'_>, _: &Crate) { - AST_FORMAT_ARGS.with(|ast_format_args| { - let result = ast_format_args.set(mem::take(&mut self.format_args)); - debug_assert!(result.is_ok()); - }); + self.storage.set(mem::take(&mut self.format_args)); } } diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 26c6859233d..ff6ee0d10ad 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro_call_first_node, MacroCall}; +use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; @@ -236,13 +236,15 @@ declare_clippy_lint! { #[derive(Default)] pub struct Write { + format_args: FormatArgsStorage, in_debug_impl: bool, allow_print_in_tests: bool, } impl Write { - pub fn new(allow_print_in_tests: bool) -> Self { + pub fn new(format_args: FormatArgsStorage, allow_print_in_tests: bool) -> Self { Self { + format_args, allow_print_in_tests, ..Default::default() } @@ -307,7 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { _ => return, } - if let Some(format_args) = find_format_args(cx, expr, macro_call.expn) { + if let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { // ignore `writeln!(w)` and `write!(v, some_macro!())` if format_args.span.from_expansion() { return; @@ -315,15 +317,15 @@ impl<'tcx> LateLintPass<'tcx> for Write { match diag_name { sym::print_macro | sym::eprint_macro | sym::write_macro => { - check_newline(cx, &format_args, ¯o_call, name); + check_newline(cx, format_args, ¯o_call, name); }, sym::println_macro | sym::eprintln_macro | sym::writeln_macro => { - check_empty_string(cx, &format_args, ¯o_call, name); + check_empty_string(cx, format_args, ¯o_call, name); }, _ => {}, } - check_literal(cx, &format_args, name); + check_literal(cx, format_args, name); if !self.in_debug_impl { for piece in &format_args.template { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 99d7aba2f7a..4c603bda770 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -193,6 +193,21 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option< None } +/// Checks if the given local has an initializer or is from something other than a `let` statement +/// +/// e.g. returns true for `x` in `fn f(x: usize) { .. }` and `let x = 1;` but false for `let x;` +pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool { + for (_, node) in cx.tcx.hir().parent_iter(local) { + match node { + Node::Pat(..) | Node::PatField(..) => {}, + Node::LetStmt(let_stmt) => return let_stmt.init.is_some(), + _ => return true, + } + } + + false +} + /// Returns `true` if the given `NodeId` is inside a constant context /// /// # Example @@ -1499,15 +1514,18 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { } /// Checks whether the given `Expr` is a range equivalent to a `RangeFull`. +/// /// For the lower bound, this means that: /// - either there is none /// - or it is the smallest value that can be represented by the range's integer type +/// /// For the upper bound, this means that: /// - either there is none /// - or it is the largest value that can be represented by the range's integer type and is /// inclusive /// - or it is a call to some container's `len` method and is exclusive, and the range is passed to /// a method call on that same container (e.g. `v.drain(..v.len())`) +/// /// If the given `Expr` is not some kind of range, the function returns `false`. pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { let ty = cx.typeck_results().expr_ty(expr); diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 257dd76ab15..8daab9b0d92 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -5,15 +5,13 @@ use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{Lrc, OnceLock}; use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; -use std::cell::OnceCell; use std::ops::ControlFlow; -use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ sym::assert_eq_macro, @@ -388,50 +386,44 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> } } -thread_local! { - /// We preserve the [`FormatArgs`] structs from the early pass for use in the late pass to be - /// able to access the many features of a [`LateContext`]. - /// - /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an - /// assumption that the early pass that populates the map and the later late passes will all be - /// running on the same thread. - #[doc(hidden)] - pub static AST_FORMAT_ARGS: OnceCell<FxHashMap<Span, Rc<FormatArgs>>> = { - static CALLED: AtomicBool = AtomicBool::new(false); - debug_assert!( - !CALLED.swap(true, Ordering::SeqCst), - "incorrect assumption: `AST_FORMAT_ARGS` should only be accessed by a single thread", - ); - - OnceCell::new() - }; -} +/// Stores AST [`FormatArgs`] nodes for use in late lint passes, as they are in a desugared form in +/// the HIR +#[derive(Default, Clone)] +pub struct FormatArgsStorage(Lrc<OnceLock<FxHashMap<Span, FormatArgs>>>); -/// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of -/// `expn_id` -pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<Rc<FormatArgs>> { - let format_args_expr = for_each_expr(start, |expr| { - let ctxt = expr.span.ctxt(); - if ctxt.outer_expn().is_descendant_of(expn_id) { - if macro_backtrace(expr.span) - .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) - .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl)) - { - ControlFlow::Break(expr) +impl FormatArgsStorage { + /// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of + /// `expn_id` + /// + /// See also [`find_format_arg_expr`] + pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> { + let format_args_expr = for_each_expr(start, |expr| { + let ctxt = expr.span.ctxt(); + if ctxt.outer_expn().is_descendant_of(expn_id) { + if macro_backtrace(expr.span) + .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) + .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl)) + { + ControlFlow::Break(expr) + } else { + ControlFlow::Continue(Descend::Yes) + } } else { - ControlFlow::Continue(Descend::Yes) + ControlFlow::Continue(Descend::No) } - } else { - ControlFlow::Continue(Descend::No) - } - })?; + })?; - AST_FORMAT_ARGS.with(|ast_format_args| { - ast_format_args - .get()? - .get(&format_args_expr.span.with_parent(None)) - .cloned() - }) + debug_assert!(self.0.get().is_some(), "`FormatArgsStorage` not yet populated"); + + self.0.get()?.get(&format_args_expr.span.with_parent(None)) + } + + /// Should only be called by `FormatArgsCollector` + pub fn set(&self, format_args: FxHashMap<Span, FormatArgs>) { + self.0 + .set(format_args) + .expect("`FormatArgsStorage::set` should only be called once"); + } } /// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index ff9f06531ea..8ee7d87acb3 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -3,7 +3,7 @@ // of terminologies might not be relevant in the context of Clippy. Note that its behavior might // differ from the time of `rustc` even if the name stays the same. -use clippy_config::msrvs::Msrv; +use clippy_config::msrvs::{self, Msrv}; use hir::LangItem; use rustc_attr::StableSince; use rustc_const_eval::transform::check_consts::ConstCx; @@ -42,7 +42,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) for bb in &*body.basic_blocks { check_terminator(tcx, body, bb.terminator(), msrv)?; for stmt in &bb.statements { - check_statement(tcx, body, def_id, stmt)?; + check_statement(tcx, body, def_id, stmt, msrv)?; } } Ok(()) @@ -102,13 +102,14 @@ fn check_rvalue<'tcx>( def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span, + msrv: &Msrv, ) -> McfResult { match rvalue { Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - check_place(tcx, *place, span, body) + check_place(tcx, *place, span, body, msrv) }, - Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body), + Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) | Rvalue::Cast( @@ -122,7 +123,7 @@ fn check_rvalue<'tcx>( | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer), operand, _, - ) => check_operand(tcx, operand, span, body), + ) => check_operand(tcx, operand, span, body, msrv), Rvalue::Cast( CastKind::PointerCoercion( PointerCoercion::UnsafeFnPointer @@ -133,15 +134,13 @@ fn check_rvalue<'tcx>( _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => { - let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { - deref_ty - } else { + let Some(pointee_ty) = cast_ty.builtin_deref(true) else { // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { - check_operand(tcx, op, span, body)?; + check_operand(tcx, op, span, body, msrv)?; // Casting/coercing things to slices is fine. Ok(()) } else { @@ -162,8 +161,8 @@ fn check_rvalue<'tcx>( )), // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) => { - check_operand(tcx, lhs, span, body)?; - check_operand(tcx, rhs, span, body)?; + check_operand(tcx, lhs, span, body, msrv)?; + check_operand(tcx, rhs, span, body, msrv)?; let ty = lhs.ty(body, tcx); if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) @@ -179,14 +178,14 @@ fn check_rvalue<'tcx>( Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { - check_operand(tcx, operand, span, body) + check_operand(tcx, operand, span, body, msrv) } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } }, Rvalue::Aggregate(_, operands) => { for operand in operands { - check_operand(tcx, operand, span, body)?; + check_operand(tcx, operand, span, body, msrv)?; } Ok(()) }, @@ -198,28 +197,29 @@ fn check_statement<'tcx>( body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>, + msrv: &Msrv, ) -> McfResult { let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(box (place, rval)) => { - check_place(tcx, *place, span, body)?; - check_rvalue(tcx, body, def_id, rval, span) + check_place(tcx, *place, span, body, msrv)?; + check_rvalue(tcx, body, def_id, rval, span, msrv) }, - StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), + StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body, msrv), // just an assignment StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { - check_place(tcx, **place, span, body) + check_place(tcx, **place, span, body, msrv) }, - StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body), + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body, msrv), StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( rustc_middle::mir::CopyNonOverlapping { dst, src, count }, )) => { - check_operand(tcx, dst, span, body)?; - check_operand(tcx, src, span, body)?; - check_operand(tcx, count, span, body) + check_operand(tcx, dst, span, body, msrv)?; + check_operand(tcx, src, span, body, msrv)?; + check_operand(tcx, count, span, body, msrv) }, // These are all NOPs StatementKind::StorageLive(_) @@ -233,7 +233,13 @@ fn check_statement<'tcx>( } } -fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_operand<'tcx>( + tcx: TyCtxt<'tcx>, + operand: &Operand<'tcx>, + span: Span, + body: &Body<'tcx>, + msrv: &Msrv, +) -> McfResult { match operand { Operand::Move(place) => { if !place.projection.as_ref().is_empty() @@ -245,9 +251,9 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b )); } - check_place(tcx, *place, span, body) + check_place(tcx, *place, span, body, msrv) }, - Operand::Copy(place) => check_place(tcx, *place, span, body), + Operand::Copy(place) => check_place(tcx, *place, span, body, msrv), Operand::Constant(c) => match c.check_static_ptr(tcx) { Some(_) => Err((span, "cannot access `static` items in const fn".into())), None => Ok(()), @@ -255,23 +261,27 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b } } -fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>, msrv: &Msrv) -> McfResult { for (base, elem) in place.as_ref().iter_projections() { match elem { ProjectionElem::Field(..) => { - let base_ty = base.ty(body, tcx).ty; - if let Some(def) = base_ty.ty_adt_def() { - // No union field accesses in `const fn` - if def.is_union() { - return Err((span, "accessing union fields is unstable".into())); - } + if base.ty(body, tcx).ty.is_union() && !msrv.meets(msrvs::CONST_FN_UNION) { + return Err((span, "accessing union fields is unstable".into())); } }, + ProjectionElem::Deref => match base.ty(body, tcx).ty.kind() { + ty::RawPtr(_, hir::Mutability::Mut) => { + return Err((span, "dereferencing raw mut pointer in const fn is unstable".into())); + }, + ty::RawPtr(_, hir::Mutability::Not) if !msrv.meets(msrvs::CONST_RAW_PTR_DEREF) => { + return Err((span, "dereferencing raw const pointer in const fn is unstable".into())); + }, + _ => (), + }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } - | ProjectionElem::Deref | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) => {}, } @@ -304,7 +314,7 @@ fn check_terminator<'tcx>( } Ok(()) }, - TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), + TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body, msrv), TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn coroutines are unstable".into())) }, @@ -341,10 +351,10 @@ fn check_terminator<'tcx>( )); } - check_operand(tcx, func, span, body)?; + check_operand(tcx, func, span, body, msrv)?; for arg in args { - check_operand(tcx, &arg.node, span, body)?; + check_operand(tcx, &arg.node, span, body, msrv)?; } Ok(()) } else { @@ -357,7 +367,7 @@ fn check_terminator<'tcx>( msg: _, target: _, unwind: _, - } => check_operand(tcx, cond, span, body), + } => check_operand(tcx, cond, span, body, msrv), TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), } } diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index e72467edeeb..fd67e039c29 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -250,7 +250,7 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow< /// - Applicability level `Unspecified` will never be changed. /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. /// - If the default value is used and the applicability level is `MachineApplicable`, change it to -/// `HasPlaceholders` +/// `HasPlaceholders` pub fn snippet_with_applicability<'a, T: LintContext>( cx: &T, span: Span, diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index bf03c6c1601..6319c7bfa6b 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -67,8 +67,7 @@ impl<'a> Sugg<'a> { /// - Applicability level `Unspecified` will never be changed. /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. /// - If the default value is used and the applicability level is `MachineApplicable`, change it - /// to - /// `HasPlaceholders` + /// to `HasPlaceholders` pub fn hir_with_applicability( cx: &LateContext<'_>, expr: &hir::Expr<'_>, diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index c29e3feac9a..2dacc34867f 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -273,11 +273,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( let infcx = tcx.infer_ctxt().build(); let args = args .into_iter() - .map(|arg| { - arg.into().unwrap_or_else(|| { - infcx.next_ty_var(DUMMY_SP).into() - }) - }) + .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())) .collect::<Vec<_>>(); // If an effect arg was not specified, we need to specify it. @@ -795,7 +791,8 @@ fn sig_from_bounds<'tcx>( inputs = Some(i); }, ty::ClauseKind::Projection(p) - if Some(p.projection_term.def_id) == lang_items.fn_once_output() && p.projection_term.self_ty() == ty => + if Some(p.projection_term.def_id) == lang_items.fn_once_output() + && p.projection_term.self_ty() == ty => { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? @@ -956,11 +953,7 @@ pub struct AdtVariantInfo { impl AdtVariantInfo { /// Returns ADT variants ordered by size - pub fn new<'tcx>( - cx: &LateContext<'tcx>, - adt: AdtDef<'tcx>, - subst: GenericArgsRef<'tcx> - ) -> Vec<Self> { + pub fn new<'tcx>(cx: &LateContext<'tcx>, adt: AdtDef<'tcx>, subst: GenericArgsRef<'tcx>) -> Vec<Self> { let mut variants_size = adt .variants() .iter() diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 9abb4ef9b8d..2a25d51d8e5 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -16,13 +16,9 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> used_mutably: HirIdSet::default(), skip: false, }; - ExprUseVisitor::for_clippy( - cx, - expr.hir_id.owner.def_id, - &mut delegate, - ) - .walk_expr(expr) - .into_ok(); + ExprUseVisitor::for_clippy(cx, expr.hir_id.owner.def_id, &mut delegate) + .walk_expr(expr) + .into_ok(); if delegate.skip { return None; diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml index a828d123704..8c5a409e25b 100644 --- a/src/tools/clippy/lintcheck/Cargo.toml +++ b/src/tools/clippy/lintcheck/Cargo.toml @@ -13,7 +13,7 @@ default-run = "lintcheck" [dependencies] anyhow = "1.0.69" cargo_metadata = "0.15.3" -clap = { version = "4.1.8", features = ["derive", "env"] } +clap = { version = "4.4", features = ["derive", "env"] } crates_io_api = "0.8.1" crossbeam-channel = "0.5.6" flate2 = "1.0" diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 055f305eb8e..a0585ffdb45 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-05-02" +channel = "nightly-2024-05-16" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr index 103e60d8484..9177e99f8e6 100644 --- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr @@ -42,4 +42,32 @@ help: to have lints override the group set `pedantic` to a lower priority 19 | pedantic = { level = "warn", priority = -2 } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: could not compile `fail` (lib) due to 3 previous errors +error: lint group `rust_2018_idioms` has the same priority (0) as a lint + --> Cargo.toml:23:1 + | +23 | rust_2018_idioms = "warn" + | ^^^^^^^^^^^^^^^^ ------ has an implicit priority of 0 +24 | bare_trait_objects = "allow" + | ------------------ has the same priority as this lint + | + = note: the order of the lints in the table is ignored by Cargo +help: to have lints override the group set `rust_2018_idioms` to a lower priority + | +23 | rust_2018_idioms = { level = "warn", priority = -1 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: lint group `pedantic` has the same priority (0) as a lint + --> Cargo.toml:27:1 + | +27 | pedantic = "warn" + | ^^^^^^^^ ------ has an implicit priority of 0 +28 | similar_names = "allow" + | ------------- has the same priority as this lint + | + = note: the order of the lints in the table is ignored by Cargo +help: to have lints override the group set `pedantic` to a lower priority + | +27 | pedantic = { level = "warn", priority = -1 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: could not compile `fail` (lib) due to 5 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml index 4ce41f78171..e4d4af9cd23 100644 --- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml @@ -18,3 +18,11 @@ deprecated = "allow" [lints.clippy] pedantic = { level = "warn", priority = -1 } similar_names = { level = "allow", priority = -1 } + +[workspace.lints.rust] +rust_2018_idioms = "warn" +bare_trait_objects = "allow" + +[workspace.lints.clippy] +pedantic = "warn" +similar_names = "allow" diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs new file mode 100644 index 00000000000..f5e01b431ad --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs @@ -0,0 +1,260 @@ +//! Tests macro_metavars_in_unsafe with default configuration +#![feature(decl_macro, lint_reasons)] +#![warn(clippy::macro_metavars_in_unsafe)] +#![allow(clippy::no_effect)] + +#[macro_export] +macro_rules! allow_works { + ($v:expr) => { + #[expect(clippy::macro_metavars_in_unsafe)] + unsafe { + $v; + }; + }; +} + +#[macro_export] +macro_rules! simple { + ($v:expr) => { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + dbg!($v); + } + }; +} + +#[macro_export] +#[rustfmt::skip] // for some reason rustfmt rewrites $r#unsafe to r#u$nsafe, bug? +macro_rules! raw_symbol { + ($r#mod:expr, $r#unsafe:expr) => { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $r#mod; + } + $r#unsafe; + }; +} + +#[macro_export] +macro_rules! multilevel_unsafe { + ($v:expr) => { + unsafe { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $v; + } + } + }; +} + +#[macro_export] +macro_rules! in_function { + ($v:expr) => { + unsafe { + fn f() { + // function introduces a new body, so don't lint. + $v; + } + } + }; +} + +#[macro_export] +macro_rules! in_function_with_unsafe { + ($v:expr) => { + unsafe { + fn f() { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $v; + } + } + } + }; +} + +#[macro_export] +macro_rules! const_static { + ($c:expr, $s:expr) => { + unsafe { + // const and static introduces new body, don't lint + const _X: i32 = $c; + static _Y: i32 = $s; + } + }; +} + +#[macro_export] +macro_rules! const_generic_in_struct { + ($inside_unsafe:expr, $outside_unsafe:expr) => { + unsafe { + struct Ty< + const L: i32 = 1, + const M: i32 = { + 1; + unsafe { $inside_unsafe } + //~^ ERROR: this macro expands metavariables in an unsafe block + }, + const N: i32 = { $outside_unsafe }, + >; + } + }; +} + +#[macro_export] +macro_rules! fn_with_const_generic { + ($inside_unsafe:expr, $outside_unsafe:expr) => { + unsafe { + fn f<const N: usize>() { + $outside_unsafe; + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $inside_unsafe; + } + } + } + }; +} + +#[macro_export] +macro_rules! variables { + ($inside_unsafe:expr, $outside_unsafe:expr) => { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $inside_unsafe; + let inside_unsafe = 1; + inside_unsafe; + } + $outside_unsafe; + let outside_unsafe = 1; + outside_unsafe; + }; +} + +#[macro_export] +macro_rules! multiple_matchers { + ($inside_unsafe:expr, $outside_unsafe:expr) => { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $inside_unsafe; + } + $outside_unsafe; + }; + ($($v:expr, $x:expr),+) => { + $( + $v; + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $x; + } + );+ + }; +} + +#[macro_export] +macro_rules! multiple_unsafe_blocks { + ($w:expr, $x:expr, $y:expr) => { + $w; + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $x; + } + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $x; + $y; + } + }; +} + +pub macro macro2_0($v:expr) { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $v; + } +} + +// don't lint private macros with the default configuration +macro_rules! private_mac { + ($v:expr) => { + unsafe { + $v; + } + }; +} + +// don't lint exported macros that are doc(hidden) because they also aren't part of the public API +#[macro_export] +#[doc(hidden)] +macro_rules! exported_but_hidden { + ($v:expr) => { + unsafe { + $v; + } + }; +} + +// don't lint if the same metavariable is expanded in an unsafe block and then outside of one: +// unsafe {} is still needed at callsite so not problematic +#[macro_export] +macro_rules! does_require_unsafe { + ($v:expr) => { + unsafe { + $v; + } + $v; + }; +} + +#[macro_export] +macro_rules! unsafe_from_root_ctxt { + ($v:expr) => { + // Expands to unsafe { 1 }, but the unsafe block is from the root ctxt and not this macro, + // so no warning. + $v; + }; +} + +// invoked from another macro, should still generate a warning +#[macro_export] +macro_rules! nested_macro_helper { + ($v:expr) => {{ + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + $v; + } + }}; +} + +#[macro_export] +macro_rules! nested_macros { + ($v:expr, $v2:expr) => {{ + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + nested_macro_helper!($v); + $v; + } + }}; +} + +fn main() { + allow_works!(1); + simple!(1); + raw_symbol!(1, 1); + multilevel_unsafe!(1); + in_function!(1); + in_function_with_unsafe!(1); + const_static!(1, 1); + const_generic_in_struct!(1, 1); + fn_with_const_generic!(1, 1); + variables!(1, 1); + multiple_matchers!(1, 1); + multiple_matchers!(1, 1, 1, 1); + macro2_0!(1); + private_mac!(1); + exported_but_hidden!(1); + does_require_unsafe!(1); + multiple_unsafe_blocks!(1, 1, 1); + unsafe_from_root_ctxt!(unsafe { 1 }); + nested_macros!(1, 1); +} diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr new file mode 100644 index 00000000000..d6b97f6fde1 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr @@ -0,0 +1,187 @@ +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:19:9 + | +LL | / unsafe { +LL | | +LL | | dbg!($v); +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]` + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:30:9 + | +LL | / unsafe { +LL | | +LL | | $r#mod; +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:42:13 + | +LL | / unsafe { +LL | | +LL | | $v; +LL | | } + | |_____________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:67:17 + | +LL | / unsafe { +LL | | +LL | | $v; +LL | | } + | |_________________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:95:21 + | +LL | unsafe { $inside_unsafe } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:110:17 + | +LL | / unsafe { +LL | | +LL | | $inside_unsafe; +LL | | } + | |_________________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:122:9 + | +LL | / unsafe { +LL | | +LL | | $inside_unsafe; +LL | | let inside_unsafe = 1; +LL | | inside_unsafe; +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:137:9 + | +LL | / unsafe { +LL | | +LL | | $inside_unsafe; +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:146:13 + | +LL | / unsafe { +LL | | +LL | | $x; +LL | | } + | |_____________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:171:5 + | +LL | / unsafe { +LL | | +LL | | $v; +LL | | } + | |_____^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:158:9 + | +LL | / unsafe { +LL | | +LL | | $x; +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:162:9 + | +LL | / unsafe { +LL | | +LL | | $x; +LL | | $y; +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:222:9 + | +LL | / unsafe { +LL | | +LL | | $v; +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:232:9 + | +LL | / unsafe { +LL | | +LL | | nested_macro_helper!($v); +LL | | $v; +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + +error: aborting due to 14 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml new file mode 100644 index 00000000000..d4bbc2a1be8 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml @@ -0,0 +1 @@ +warn-unsafe-macro-metavars-in-private-macros = true diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs new file mode 100644 index 00000000000..2bbe1fa7b7f --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs @@ -0,0 +1,15 @@ +//! Tests macro_metavars_in_unsafe with private (non-exported) macros +#![warn(clippy::macro_metavars_in_unsafe)] + +macro_rules! mac { + ($v:expr) => { + unsafe { + //~^ ERROR: this macro expands metavariables in an unsafe block + dbg!($v); + } + }; +} + +fn main() { + mac!(1); +} diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr new file mode 100644 index 00000000000..f9c418b2218 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr @@ -0,0 +1,17 @@ +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/private/test.rs:6:9 + | +LL | / unsafe { +LL | | +LL | | dbg!($v); +LL | | } + | |_________^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/panic/clippy.toml b/src/tools/clippy/tests/ui-toml/panic/clippy.toml new file mode 100644 index 00000000000..5d6230d092c --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/panic/clippy.toml @@ -0,0 +1 @@ +allow-panic-in-tests = true diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.rs b/src/tools/clippy/tests/ui-toml/panic/panic.rs new file mode 100644 index 00000000000..618a37ddfc5 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/panic/panic.rs @@ -0,0 +1,54 @@ +//@compile-flags: --test +#![warn(clippy::panic)] + +fn main() { + enum Enam { + A, + } + let a = Enam::A; + match a { + Enam::A => {}, + _ => panic!(""), + } +} + +#[test] +fn lonely_test() { + enum Enam { + A, + } + let a = Enam::A; + match a { + Enam::A => {}, + _ => panic!(""), + } +} + +#[cfg(test)] +mod tests { + // should not lint in `#[cfg(test)]` modules + #[test] + fn test_fn() { + enum Enam { + A, + } + let a = Enam::A; + match a { + Enam::A => {}, + _ => panic!(""), + } + + bar(); + } + + fn bar() { + enum Enam { + A, + } + let a = Enam::A; + match a { + Enam::A => {}, + _ => panic!(""), + } + } +} diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.stderr b/src/tools/clippy/tests/ui-toml/panic/panic.stderr new file mode 100644 index 00000000000..bf7503e086c --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/panic/panic.stderr @@ -0,0 +1,11 @@ +error: `panic` should not be present in production code + --> tests/ui-toml/panic/panic.rs:11:14 + | +LL | _ => panic!(""), + | ^^^^^^^^^^ + | + = note: `-D clippy::panic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panic)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml b/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml new file mode 100644 index 00000000000..5381e70a939 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml @@ -0,0 +1,2 @@ +# Ignore `From`, `TryFrom`, `FromStr` by default +# allow-renamed-params-for = [] diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml b/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml new file mode 100644 index 00000000000..9b3853e7696 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml @@ -0,0 +1,2 @@ +# Ignore `From`, `TryFrom`, `FromStr` by default +allow-renamed-params-for = [ "..", "std::ops::Add", "renamed_function_params::MyTrait" ] diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr new file mode 100644 index 00000000000..2d700f60759 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr @@ -0,0 +1,46 @@ +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:30:18 + | +LL | fn eq(&self, rhs: &Self) -> bool { + | ^^^ help: consider using the default name: `other` + | + = note: `-D clippy::renamed-function-params` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::renamed_function_params)]` + +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:34:18 + | +LL | fn ne(&self, rhs: &Self) -> bool { + | ^^^ help: consider using the default name: `other` + +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:48:19 + | +LL | fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `extend` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the default name: `val` + +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31 + | +LL | fn hash<H: Hasher>(&self, states: &mut H) { + | ^^^^^^ help: consider using the default name: `state` + +error: renamed function parameters of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30 + | +LL | fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) { + | ^^^^ ^^^^^^ + | +help: consider using the default names + | +LL | fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) { + | ~~~~ ~~~~~ + +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:80:18 + | +LL | fn add(self, b: B) -> C { + | ^ help: consider using the default name: `rhs` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr new file mode 100644 index 00000000000..e57554fa613 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr @@ -0,0 +1,34 @@ +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:30:18 + | +LL | fn eq(&self, rhs: &Self) -> bool { + | ^^^ help: consider using the default name: `other` + | + = note: `-D clippy::renamed-function-params` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::renamed_function_params)]` + +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:34:18 + | +LL | fn ne(&self, rhs: &Self) -> bool { + | ^^^ help: consider using the default name: `other` + +error: renamed function parameter of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31 + | +LL | fn hash<H: Hasher>(&self, states: &mut H) { + | ^^^^^^ help: consider using the default name: `state` + +error: renamed function parameters of trait impl + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30 + | +LL | fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) { + | ^^^^ ^^^^^^ + | +help: consider using the default names + | +LL | fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) { + | ~~~~ ~~~~~ + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs new file mode 100644 index 00000000000..f3eb910abbd --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs @@ -0,0 +1,110 @@ +//@no-rustfix +//@revisions: default extend +//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/renamed_function_params/default +//@[extend] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/renamed_function_params/extend +#![warn(clippy::renamed_function_params)] +#![allow(clippy::partialeq_ne_impl, clippy::to_string_trait_impl)] +#![allow(unused)] + +use std::hash::{Hash, Hasher}; + +struct A; +impl From<A> for String { + fn from(_value: A) -> Self { + String::new() + } +} +impl ToString for A { + fn to_string(&self) -> String { + String::new() + } +} + +struct B(u32); +impl std::convert::From<B> for String { + fn from(b: B) -> Self { + b.0.to_string() + } +} +impl PartialEq for B { + fn eq(&self, rhs: &Self) -> bool { + //~^ ERROR: renamed function parameter of trait impl + self.0 == rhs.0 + } + fn ne(&self, rhs: &Self) -> bool { + //~^ ERROR: renamed function parameter of trait impl + self.0 != rhs.0 + } +} + +trait MyTrait { + fn foo(&self, val: u8); + fn bar(a: u8, b: u8); + fn baz(self, _val: u8); + fn quz(&self, _: u8); +} + +impl MyTrait for B { + fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `extend` + fn bar(_a: u8, _: u8) {} + fn baz(self, val: u8) {} + fn quz(&self, val: u8) {} +} + +impl Hash for B { + fn hash<H: Hasher>(&self, states: &mut H) { + //~^ ERROR: renamed function parameter of trait impl + self.0.hash(states); + } + fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) { + //~^ ERROR: renamed function parameters of trait impl + for d in date { + d.hash(states); + } + } +} + +impl B { + fn totally_irrelevant(&self, right: bool) {} + fn some_fn(&self, other: impl MyTrait) {} +} + +#[derive(Copy, Clone)] +enum C { + A, + B(u32), +} + +impl std::ops::Add<B> for C { + type Output = C; + fn add(self, b: B) -> C { + // only lint in `extend` + C::B(b.0) + } +} + +impl From<A> for C { + fn from(_: A) -> C { + C::A + } +} + +trait CustomTraitA { + fn foo(&self, other: u32); +} +trait CustomTraitB { + fn bar(&self, value: u8); +} + +macro_rules! impl_trait { + ($impl_for:ident, $tr:ty, $fn_name:ident, $t:ty) => { + impl $tr for $impl_for { + fn $fn_name(&self, v: $t) {} + } + }; +} + +impl_trait!(C, CustomTraitA, foo, u32); +impl_trait!(C, CustomTraitB, bar, u8); + +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs index 7f28efd676f..f02bd07cfe7 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs @@ -40,3 +40,9 @@ fn main() { let _ = HashMap; let _: usize = 64_usize; } + +mod useless_attribute { + // Regression test for https://github.com/rust-lang/rust-clippy/issues/12753 + #[allow(clippy::disallowed_types)] + use std::collections::HashMap; +} diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 722e9b3bc8d..5cf9c0fb271 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -8,8 +8,10 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-expect-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings + allow-panic-in-tests allow-print-in-tests allow-private-module-inception + allow-renamed-params-for allow-unwrap-in-tests allow-useless-vec-in-tests allowed-dotfiles @@ -74,6 +76,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect vec-box-size-threshold verbose-bit-mask-threshold warn-on-all-wildcard-imports + warn-unsafe-macro-metavars-in-private-macros --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:2:1 | LL | foobar = 42 @@ -89,8 +92,10 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-expect-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings + allow-panic-in-tests allow-print-in-tests allow-private-module-inception + allow-renamed-params-for allow-unwrap-in-tests allow-useless-vec-in-tests allowed-dotfiles @@ -155,6 +160,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect vec-box-size-threshold verbose-bit-mask-threshold warn-on-all-wildcard-imports + warn-unsafe-macro-metavars-in-private-macros --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:4:1 | LL | barfoo = 53 @@ -170,8 +176,10 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-expect-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings + allow-panic-in-tests allow-print-in-tests allow-private-module-inception + allow-renamed-params-for allow-unwrap-in-tests allow-useless-vec-in-tests allowed-dotfiles @@ -236,6 +244,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni vec-box-size-threshold verbose-bit-mask-threshold warn-on-all-wildcard-imports + warn-unsafe-macro-metavars-in-private-macros --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:7:1 | LL | allow_mixed_uninlined_format_args = true diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed index 8387c7d6156..70ab43b49b3 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.fixed +++ b/src/tools/clippy/tests/ui/assigning_clones.fixed @@ -62,6 +62,16 @@ fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFr mut_thing.clone_from(ref_thing + ref_thing); } +fn clone_method_macro() { + let mut s = String::from(""); + s.clone_from(&format!("{} {}", "hello", "world")); +} + +fn clone_function_macro() { + let mut s = String::from(""); + Clone::clone_from(&mut s, &format!("{} {}", "hello", "world")); +} + fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom { let mut a = HasCloneFrom; for _ in 1..10 { @@ -86,6 +96,12 @@ fn assign_to_uninit_mut_var(b: HasCloneFrom) { a = b.clone(); } +fn late_init_let_tuple() { + let (p, q): (String, String); + p = "ghi".to_string(); + q = p.clone(); +} + #[derive(Clone)] pub struct HasDeriveClone; @@ -208,6 +224,16 @@ fn owned_function_val(mut mut_thing: String, ref_str: &str) { ToOwned::clone_into(ref_str, &mut mut_thing); } +fn owned_method_macro() { + let mut s = String::from(""); + format!("{} {}", "hello", "world").clone_into(&mut s); +} + +fn owned_function_macro() { + let mut s = String::from(""); + ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s); +} + struct FakeToOwned; impl FakeToOwned { /// This looks just like `ToOwned::to_owned` diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs index 6f4da9f652c..9699fed100c 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.rs +++ b/src/tools/clippy/tests/ui/assigning_clones.rs @@ -62,6 +62,16 @@ fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFr *mut_thing = (ref_thing + ref_thing).clone(); } +fn clone_method_macro() { + let mut s = String::from(""); + s = format!("{} {}", "hello", "world").clone(); +} + +fn clone_function_macro() { + let mut s = String::from(""); + s = Clone::clone(&format!("{} {}", "hello", "world")); +} + fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom { let mut a = HasCloneFrom; for _ in 1..10 { @@ -86,6 +96,12 @@ fn assign_to_uninit_mut_var(b: HasCloneFrom) { a = b.clone(); } +fn late_init_let_tuple() { + let (p, q): (String, String); + p = "ghi".to_string(); + q = p.clone(); +} + #[derive(Clone)] pub struct HasDeriveClone; @@ -208,6 +224,16 @@ fn owned_function_val(mut mut_thing: String, ref_str: &str) { mut_thing = ToOwned::to_owned(ref_str); } +fn owned_method_macro() { + let mut s = String::from(""); + s = format!("{} {}", "hello", "world").to_owned(); +} + +fn owned_function_macro() { + let mut s = String::from(""); + s = ToOwned::to_owned(&format!("{} {}", "hello", "world")); +} + struct FakeToOwned; impl FakeToOwned { /// This looks just like `ToOwned::to_owned` diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr index 793927bd1cb..a68516376ab 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.stderr +++ b/src/tools/clippy/tests/ui/assigning_clones.stderr @@ -62,64 +62,88 @@ LL | *mut_thing = (ref_thing + ref_thing).clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing + ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:68:9 + --> tests/ui/assigning_clones.rs:67:5 + | +LL | s = format!("{} {}", "hello", "world").clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `s.clone_from(&format!("{} {}", "hello", "world"))` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:72:5 + | +LL | s = Clone::clone(&format!("{} {}", "hello", "world")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"))` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:78:9 | LL | a = b.clone(); | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:133:5 + --> tests/ui/assigning_clones.rs:149:5 | LL | a = b.clone(); | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:140:5 + --> tests/ui/assigning_clones.rs:156:5 | LL | a = b.clone(); | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:141:5 + --> tests/ui/assigning_clones.rs:157:5 | LL | a = c.to_owned(); | ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:171:5 + --> tests/ui/assigning_clones.rs:187:5 | LL | *mut_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:175:5 + --> tests/ui/assigning_clones.rs:191:5 | LL | mut_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:196:5 + --> tests/ui/assigning_clones.rs:212:5 | LL | **mut_box_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:200:5 + --> tests/ui/assigning_clones.rs:216:5 | LL | **mut_box_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:204:5 + --> tests/ui/assigning_clones.rs:220:5 | LL | *mut_thing = ToOwned::to_owned(ref_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:208:5 + --> tests/ui/assigning_clones.rs:224:5 | LL | mut_thing = ToOwned::to_owned(ref_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)` -error: aborting due to 20 previous errors +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:229:5 + | +LL | s = format!("{} {}", "hello", "world").to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `format!("{} {}", "hello", "world").clone_into(&mut s)` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:234:5 + | +LL | s = ToOwned::to_owned(&format!("{} {}", "hello", "world")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s)` + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed new file mode 100644 index 00000000000..9877991f183 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed @@ -0,0 +1,47 @@ +#![warn(clippy::doc_lazy_continuation)] + +/// > blockquote with +/// > lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn first() {} + +/// > blockquote with no +/// > lazy continuation +fn first_nowarn() {} + +/// > blockquote with no +/// +/// lazy continuation +fn two_nowarn() {} + +/// > nest here +/// > +/// > > nest here +/// > > lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn two() {} + +/// > nest here +/// > +/// > > nest here +/// > > lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn three() {} + +/// > * > nest here +/// > > lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn four() {} + +/// > * > nest here +/// > > lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn four_point_1() {} + +/// * > nest here lazy continuation +fn five() {} + +/// 1. > nest here +/// > lazy continuation (this results in strange indentation, but still works) +//~^ ERROR: doc quote missing `>` marker +fn six() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs new file mode 100644 index 00000000000..587b2fdd533 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs @@ -0,0 +1,47 @@ +#![warn(clippy::doc_lazy_continuation)] + +/// > blockquote with +/// lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn first() {} + +/// > blockquote with no +/// > lazy continuation +fn first_nowarn() {} + +/// > blockquote with no +/// +/// lazy continuation +fn two_nowarn() {} + +/// > nest here +/// > +/// > > nest here +/// > lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn two() {} + +/// > nest here +/// > +/// > > nest here +/// lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn three() {} + +/// > * > nest here +/// lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn four() {} + +/// > * > nest here +/// lazy continuation +//~^ ERROR: doc quote missing `>` marker +fn four_point_1() {} + +/// * > nest here lazy continuation +fn five() {} + +/// 1. > nest here +/// lazy continuation (this results in strange indentation, but still works) +//~^ ERROR: doc quote missing `>` marker +fn six() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr new file mode 100644 index 00000000000..975184a01c3 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr @@ -0,0 +1,76 @@ +error: doc quote missing `>` marker + --> tests/ui/doc/doc_lazy_blockquote.rs:4:5 + | +LL | /// lazy continuation + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` + = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` +help: add markers to start of line + | +LL | /// > lazy continuation + | + + +error: doc quote missing `>` marker + --> tests/ui/doc/doc_lazy_blockquote.rs:20:5 + | +LL | /// > lazy continuation + | ^^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: add markers to start of line + | +LL | /// > > lazy continuation + | + + +error: doc quote missing `>` marker + --> tests/ui/doc/doc_lazy_blockquote.rs:27:5 + | +LL | /// lazy continuation + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: add markers to start of line + | +LL | /// > > lazy continuation + | +++ + +error: doc quote missing `>` marker + --> tests/ui/doc/doc_lazy_blockquote.rs:32:5 + | +LL | /// lazy continuation + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: add markers to start of line + | +LL | /// > > lazy continuation + | +++++++ + +error: doc quote missing `>` marker + --> tests/ui/doc/doc_lazy_blockquote.rs:37:5 + | +LL | /// lazy continuation + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: add markers to start of line + | +LL | /// > > lazy continuation + | +++++ + +error: doc quote missing `>` marker + --> tests/ui/doc/doc_lazy_blockquote.rs:45:5 + | +LL | /// lazy continuation (this results in strange indentation, but still works) + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: add markers to start of line + | +LL | /// > lazy continuation (this results in strange indentation, but still works) + | + + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed new file mode 100644 index 00000000000..409e6b0bc22 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed @@ -0,0 +1,77 @@ +#![warn(clippy::doc_lazy_continuation)] + +/// 1. nest here +/// lazy continuation +//~^ ERROR: doc list item missing indentation +fn one() {} + +/// 1. first line +/// lazy list continuations don't make warnings with this lint +//~^ ERROR: doc list item missing indentation +/// because they don't have the +//~^ ERROR: doc list item missing indentation +fn two() {} + +/// - nest here +/// lazy continuation +//~^ ERROR: doc list item missing indentation +fn three() {} + +/// - first line +/// lazy list continuations don't make warnings with this lint +//~^ ERROR: doc list item missing indentation +/// because they don't have the +//~^ ERROR: doc list item missing indentation +fn four() {} + +/// - nest here +/// lazy continuation +//~^ ERROR: doc list item missing indentation +fn five() {} + +/// - - first line +/// this will warn on the lazy continuation +//~^ ERROR: doc list item missing indentation +/// and so should this +//~^ ERROR: doc list item missing indentation +fn six() {} + +/// - - first line +/// +/// this is not a lazy continuation +fn seven() {} + +#[rustfmt::skip] +// https://github.com/rust-lang/rust-clippy/pull/12770#issuecomment-2118601768 +/// Returns a list of ProtocolDescriptors from a Serde JSON input. +/// +/// Defined Protocol Identifiers for the Protocol Descriptor +/// We intentionally omit deprecated profile identifiers. +/// From Bluetooth Assigned Numbers: +/// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery +/// +/// # Arguments +/// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors +/// to set up. Example: +/// 'protocol_descriptors': [ +//~^ ERROR: doc list item missing indentation +/// { +/// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP +/// 'params': [ +/// { +/// 'data': 0x0103 # to indicate 1.3 +/// }, +/// { +/// 'data': 0x0105 # to indicate 1.5 +/// } +/// ] +/// }, +/// { +/// 'protocol': 1, # u64 Representation of ProtocolIdentifier::SDP +/// 'params': [{ +/// 'data': 0x0019 +/// }] +/// } +/// ] +//~^ ERROR: doc list item missing indentation +fn eight() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs new file mode 100644 index 00000000000..30ab448a113 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs @@ -0,0 +1,77 @@ +#![warn(clippy::doc_lazy_continuation)] + +/// 1. nest here +/// lazy continuation +//~^ ERROR: doc list item missing indentation +fn one() {} + +/// 1. first line +/// lazy list continuations don't make warnings with this lint +//~^ ERROR: doc list item missing indentation +/// because they don't have the +//~^ ERROR: doc list item missing indentation +fn two() {} + +/// - nest here +/// lazy continuation +//~^ ERROR: doc list item missing indentation +fn three() {} + +/// - first line +/// lazy list continuations don't make warnings with this lint +//~^ ERROR: doc list item missing indentation +/// because they don't have the +//~^ ERROR: doc list item missing indentation +fn four() {} + +/// - nest here +/// lazy continuation +//~^ ERROR: doc list item missing indentation +fn five() {} + +/// - - first line +/// this will warn on the lazy continuation +//~^ ERROR: doc list item missing indentation +/// and so should this +//~^ ERROR: doc list item missing indentation +fn six() {} + +/// - - first line +/// +/// this is not a lazy continuation +fn seven() {} + +#[rustfmt::skip] +// https://github.com/rust-lang/rust-clippy/pull/12770#issuecomment-2118601768 +/// Returns a list of ProtocolDescriptors from a Serde JSON input. +/// +/// Defined Protocol Identifiers for the Protocol Descriptor +/// We intentionally omit deprecated profile identifiers. +/// From Bluetooth Assigned Numbers: +/// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery +/// +/// # Arguments +/// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors +/// to set up. Example: +/// 'protocol_descriptors': [ +//~^ ERROR: doc list item missing indentation +/// { +/// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP +/// 'params': [ +/// { +/// 'data': 0x0103 # to indicate 1.3 +/// }, +/// { +/// 'data': 0x0105 # to indicate 1.5 +/// } +/// ] +/// }, +/// { +/// 'protocol': 1, # u64 Representation of ProtocolIdentifier::SDP +/// 'params': [{ +/// 'data': 0x0019 +/// }] +/// } +/// ] +//~^ ERROR: doc list item missing indentation +fn eight() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr new file mode 100644 index 00000000000..ddfdc49340c --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr @@ -0,0 +1,136 @@ +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:4:5 + | +LL | /// lazy continuation + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line + = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` +help: indent this line + | +LL | /// lazy continuation + | +++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:9:5 + | +LL | /// lazy list continuations don't make warnings with this lint + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// lazy list continuations don't make warnings with this lint + | +++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:11:5 + | +LL | /// because they don't have the + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// because they don't have the + | +++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:16:5 + | +LL | /// lazy continuation + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// lazy continuation + | ++++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:21:5 + | +LL | /// lazy list continuations don't make warnings with this lint + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// lazy list continuations don't make warnings with this lint + | ++++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:23:5 + | +LL | /// because they don't have the + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// because they don't have the + | ++++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:28:5 + | +LL | /// lazy continuation + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// lazy continuation + | ++++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:33:5 + | +LL | /// this will warn on the lazy continuation + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// this will warn on the lazy continuation + | ++++++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:35:5 + | +LL | /// and so should this + | ^^^^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// and so should this + | ++ + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:56:5 + | +LL | /// 'protocol_descriptors': [ + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// 'protocol_descriptors': [ + | + + +error: doc list item missing indentation + --> tests/ui/doc/doc_lazy_list.rs:75:5 + | +LL | /// ] + | ^ + | + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line + | +LL | /// ] + | + + +error: aborting due to 11 previous errors + diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs index d51e7e37beb..97cf4a69682 100644 --- a/src/tools/clippy/tests/ui/duplicated_attributes.rs +++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs @@ -1,5 +1,5 @@ //@aux-build:proc_macro_attr.rs - +#![feature(rustc_attrs)] #![warn(clippy::duplicated_attributes)] #![cfg(any(unix, windows))] #![allow(dead_code)] @@ -20,6 +20,10 @@ fn foo() {} #[cfg(unix)] // cfgs are not handled fn bar() {} +// No warning: +#[rustc_on_unimplemented(on(_Self = "&str", label = "`a"), on(_Self = "alloc::string::String", label = "a"))] +trait Abc {} + #[proc_macro_attr::duplicated_attr()] // Should not warn! fn babar() {} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed index 8c253bfd99a..f9ce1defda1 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed +++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed @@ -1,3 +1,4 @@ +#![feature(const_int_from_str)] #![warn(clippy::from_str_radix_10)] mod some_mod { @@ -59,3 +60,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { Ok(()) } + +fn issue_12732() { + const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10); + const B: () = { + let _ = u32::from_str_radix("123", 10); + }; + const fn foo() { + let _ = u32::from_str_radix("123", 10); + } +} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs index e9d02215710..2d5b351f8da 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.rs +++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs @@ -1,3 +1,4 @@ +#![feature(const_int_from_str)] #![warn(clippy::from_str_radix_10)] mod some_mod { @@ -59,3 +60,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { Ok(()) } + +fn issue_12732() { + const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10); + const B: () = { + let _ = u32::from_str_radix("123", 10); + }; + const fn foo() { + let _ = u32::from_str_radix("123", 10); + } +} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr index 4aa84eca261..01a1bf8940a 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr +++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr @@ -1,5 +1,5 @@ error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:28:5 + --> tests/ui/from_str_radix_10.rs:29:5 | LL | u32::from_str_radix("30", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::<u32>()` @@ -8,43 +8,43 @@ LL | u32::from_str_radix("30", 10)?; = help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:31:5 + --> tests/ui/from_str_radix_10.rs:32:5 | LL | i64::from_str_radix("24", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::<i64>()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:33:5 + --> tests/ui/from_str_radix_10.rs:34:5 | LL | isize::from_str_radix("100", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::<isize>()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:35:5 + --> tests/ui/from_str_radix_10.rs:36:5 | LL | u8::from_str_radix("7", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::<u8>()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:37:5 + --> tests/ui/from_str_radix_10.rs:38:5 | LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::<u16>()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:39:5 + --> tests/ui/from_str_radix_10.rs:40:5 | LL | i128::from_str_radix(Test + Test, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::<i128>()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:43:5 + --> tests/ui/from_str_radix_10.rs:44:5 | LL | i32::from_str_radix(string, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::<i32>()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:47:5 + --> tests/ui/from_str_radix_10.rs:48:5 | LL | i32::from_str_radix(&stringier, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()` diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr index a926570b60a..3c0382767c3 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms.stderr @@ -2,7 +2,7 @@ error: this match arm has an identical body to the `_` wildcard arm --> tests/ui/match_same_arms.rs:12:9 | LL | Abc::A => 0, - | ^^^^^^^^^^^ help: try removing the arm + | ^^^^^^^^^^^^^ help: try removing the arm | = help: or try changing either arm body note: `_` wildcard arm here @@ -17,106 +17,114 @@ error: this match arm has an identical body to another arm --> tests/ui/match_same_arms.rs:18:9 | LL | (1, .., 3) => 42, - | ----------^^^^^^ - | | - | help: try merging the arm patterns: `(1, .., 3) | (.., 3)` + | ^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms.rs:19:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | (1, .., 3) | (.., 3) => 42, + | ~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - (.., 3) => 42, | -LL | (.., 3) => 42, - | ^^^^^^^^^^^^^ error: this match arm has an identical body to another arm --> tests/ui/match_same_arms.rs:25:9 | LL | 51 => 1, - | --^^^^^ - | | - | help: try merging the arm patterns: `51 | 42` + | ^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms.rs:24:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 51 | 42 => 1, + | ~~~~~~~ +help: and remove this obsolete arm + | +LL - 42 => 1, | -LL | 42 => 1, - | ^^^^^^^ error: this match arm has an identical body to another arm --> tests/ui/match_same_arms.rs:26:9 | LL | 41 => 2, - | --^^^^^ - | | - | help: try merging the arm patterns: `41 | 52` + | ^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms.rs:27:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 41 | 52 => 2, + | ~~~~~~~ +help: and remove this obsolete arm + | +LL - 52 => 2, | -LL | 52 => 2, - | ^^^^^^^ error: this match arm has an identical body to another arm --> tests/ui/match_same_arms.rs:33:9 | LL | 2 => 2, - | -^^^^^ - | | - | help: try merging the arm patterns: `2 | 1` + | ^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms.rs:32:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 2 | 1 => 2, + | ~~~~~ +help: and remove this obsolete arm + | +LL - 1 => 2, | -LL | 1 => 2, - | ^^^^^^ error: this match arm has an identical body to another arm --> tests/ui/match_same_arms.rs:35:9 | LL | 3 => 2, - | -^^^^^ - | | - | help: try merging the arm patterns: `3 | 1` + | ^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms.rs:32:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 3 | 1 => 2, + | ~~~~~ +help: and remove this obsolete arm + | +LL - 1 => 2, | -LL | 1 => 2, - | ^^^^^^ error: this match arm has an identical body to another arm --> tests/ui/match_same_arms.rs:33:9 | LL | 2 => 2, - | -^^^^^ - | | - | help: try merging the arm patterns: `2 | 3` + | ^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms.rs:35:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 2 | 3 => 2, + | ~~~~~ +help: and remove this obsolete arm + | +LL - 3 => 2, +LL + | -LL | 3 => 2, - | ^^^^^^ error: this match arm has an identical body to another arm --> tests/ui/match_same_arms.rs:52:17 | LL | CommandInfo::External { name, .. } => name.to_string(), - | ----------------------------------^^^^^^^^^^^^^^^^^^^^ - | | - | help: try merging the arm patterns: `CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms.rs:51:17 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(), + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - CommandInfo::BuiltIn { name, .. } => name.to_string(), | -LL | CommandInfo::BuiltIn { name, .. } => name.to_string(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/match_same_arms2.fixed b/src/tools/clippy/tests/ui/match_same_arms2.fixed new file mode 100644 index 00000000000..fba0cf33b3c --- /dev/null +++ b/src/tools/clippy/tests/ui/match_same_arms2.fixed @@ -0,0 +1,241 @@ +#![warn(clippy::match_same_arms)] +#![allow( + clippy::disallowed_names, + clippy::diverging_sub_expression, + clippy::uninlined_format_args, + clippy::match_single_binding, + clippy::match_like_matches_macro +)] +fn bar<T>(_: T) {} +fn foo() -> bool { + unimplemented!() +} + +fn match_same_arms() { + let _ = match 42 { + _ => { + foo(); + let mut a = 42 + [23].len() as i32; + if true { + a += 7; + } + a = -31 - a; + a + }, + }; + //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm + + let _ = match 42 { + 51 | 42 => foo(), //~ ERROR: this match arm has an identical body to another arm + _ => true, + }; + + let _ = match Some(42) { + None | Some(_) => 24, //~ ERROR: this match arm has an identical body to another arm + }; + + let _ = match Some(42) { + Some(foo) => 24, + None => 24, + }; + + let _ = match Some(42) { + Some(42) => 24, + Some(a) => 24, // bindings are different + None => 0, + }; + + let _ = match Some(42) { + Some(a) if a > 0 => 24, + Some(a) => 24, // one arm has a guard + None => 0, + }; + + match (Some(42), Some(42)) { + (None, Some(a)) | (Some(a), None) => bar(a), //~ ERROR: this match arm has an identical body to another arm + _ => (), + } + + // No warning because guards are different + let _ = match Some(42) { + Some(a) if a == 42 => a, + Some(a) if a == 24 => a, + Some(_) => 24, + None => 0, + }; + + let _ = match (Some(42), Some(42)) { + (None, Some(a)) | (Some(a), None) if a == 42 => a, //~ ERROR: this match arm has an identical body to another arm + _ => 0, + }; + + match (Some(42), Some(42)) { + (Some(a), ..) | (.., Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm + _ => (), + } + + let _ = match Some(()) { + Some(()) => 0.0, + None => -0.0, + }; + + match (Some(42), Some("")) { + (Some(a), None) => bar(a), + (None, Some(a)) => bar(a), // bindings have different types + _ => (), + } + + let x: Result<i32, &str> = Ok(3); + + // No warning because of the guard. + match x { + Ok(x) if x * x == 64 => println!("ok"), + Ok(_) => println!("ok"), + Err(_) => println!("err"), + } + + // This used to be a false positive; see issue #1996. + match x { + Ok(3) => println!("ok"), + Ok(x) if x * x == 64 => println!("ok 64"), + Ok(_) => println!("ok"), + Err(_) => println!("err"), + } + + match (x, Some(1i32)) { + (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm + _ => println!("err"), + } + + // No warning; different types for `x`. + match (x, Some(1.0f64)) { + (Ok(x), Some(_)) => println!("ok {}", x), + (Ok(_), Some(x)) => println!("ok {}", x), + _ => println!("err"), + } + + // False negative #2251. + match x { + Ok(_tmp) => println!("ok"), + Ok(_) | Ok(3) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm + Err(_) => { + unreachable!(); + }, + } + + // False positive #1390 + macro_rules! empty { + ($e:expr) => {}; + } + match 0 { + 0 => { + empty!(0); + }, + 1 => { + empty!(1); + }, + x => { + empty!(x); + }, + }; + + // still lint if the tokens are the same + match 0 { + 1 | 0 => { + empty!(0); + }, + x => { + empty!(x); + }, + } + //~^^^^^^^ ERROR: this match arm has an identical body to another arm + + match_expr_like_matches_macro_priority(); +} + +fn match_expr_like_matches_macro_priority() { + enum E { + A, + B, + C, + } + let x = E::A; + let _ans = match x { + E::A => false, + E::B => false, + _ => true, + }; +} + +fn main() { + let _ = match Some(0) { + Some(0) => 0, + Some(1) => 1, + #[cfg(feature = "foo")] + Some(2) => 2, + _ => 1, + }; + + enum Foo { + X(u32), + Y(u32), + Z(u32), + } + + // Don't lint. `Foo::X(0)` and `Foo::Z(_)` overlap with the arm in between. + let _ = match Foo::X(0) { + Foo::X(0) => 1, + Foo::X(_) | Foo::Y(_) | Foo::Z(0) => 2, + Foo::Z(_) => 1, + _ => 0, + }; + + // Suggest moving `Foo::Z(_)` up. + let _ = match Foo::X(0) { + Foo::X(0) | Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm + Foo::X(_) | Foo::Y(_) => 2, + _ => 0, + }; + + // Suggest moving `Foo::X(0)` down. + let _ = match Foo::X(0) { + Foo::Y(_) | Foo::Z(0) => 2, + Foo::Z(_) | Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm + _ => 0, + }; + + // Don't lint. + let _ = match 0 { + -2 => 1, + -5..=50 => 2, + -150..=88 => 1, + _ => 3, + }; + + struct Bar { + x: u32, + y: u32, + z: u32, + } + + // Lint. + let _ = match None { + Some(Bar { y: 10, z: 0, .. }) => 2, + None => 50, + Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm + _ => 200, + }; + + let _ = match 0 { + 0 => todo!(), + 1 => todo!(), + 2 => core::convert::identity::<u32>(todo!()), + 3 => core::convert::identity::<u32>(todo!()), + _ => 5, + }; + + let _ = match 0 { + 1 | 0 => cfg!(not_enable), + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 85ad0962eb4..8a4e3b325bb 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -2,9 +2,10 @@ #![allow( clippy::disallowed_names, clippy::diverging_sub_expression, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::match_single_binding, + clippy::match_like_matches_macro )] -//@no-rustfix fn bar<T>(_: T) {} fn foo() -> bool { unimplemented!() diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index f4c38c1af89..3d15176ccf9 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -1,18 +1,18 @@ error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms2.rs:15:9 + --> tests/ui/match_same_arms2.rs:16:9 | LL | / 42 => { LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; LL | | if true { ... | -LL | | a LL | | }, - | |_________^ help: try removing the arm +LL | | _ => { + | |________^ help: try removing the arm | = help: or try changing either arm body note: `_` wildcard arm here - --> tests/ui/match_same_arms2.rs:24:9 + --> tests/ui/match_same_arms2.rs:25:9 | LL | / _ => { LL | | foo(); @@ -26,203 +26,200 @@ LL | | }, = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:38:9 + --> tests/ui/match_same_arms2.rs:39:9 | LL | 51 => foo(), - | --^^^^^^^^^ - | | - | help: try merging the arm patterns: `51 | 42` + | ^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:37:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 51 | 42 => foo(), + | ~~~~~~~ +help: and remove this obsolete arm + | +LL - 42 => foo(), | -LL | 42 => foo(), - | ^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:44:9 + --> tests/ui/match_same_arms2.rs:45:9 | LL | None => 24, - | ----^^^^^^ - | | - | help: try merging the arm patterns: `None | Some(_)` + | ^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:43:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | None | Some(_) => 24, + | ~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - Some(_) => 24, | -LL | Some(_) => 24, - | ^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:66:9 + --> tests/ui/match_same_arms2.rs:67:9 | LL | (None, Some(a)) => bar(a), - | ---------------^^^^^^^^^^ - | | - | help: try merging the arm patterns: `(None, Some(a)) | (Some(a), None)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:65:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | (None, Some(a)) | (Some(a), None) => bar(a), + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - (Some(a), None) => bar(a), | -LL | (Some(a), None) => bar(a), - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:80:9 + --> tests/ui/match_same_arms2.rs:81:9 | LL | (None, Some(a)) if a == 42 => a, - | ---------------^^^^^^^^^^^^^^^^ - | | - | help: try merging the arm patterns: `(None, Some(a)) | (Some(a), None)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:79:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | (None, Some(a)) | (Some(a), None) if a == 42 => a, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - (Some(a), None) if a == 42 => a, | -LL | (Some(a), None) if a == 42 => a, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:85:9 + --> tests/ui/match_same_arms2.rs:86:9 | LL | (Some(a), ..) => bar(a), - | -------------^^^^^^^^^^ - | | - | help: try merging the arm patterns: `(Some(a), ..) | (.., Some(a))` + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:86:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | (Some(a), ..) | (.., Some(a)) => bar(a), + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - (.., Some(a)) => bar(a), | -LL | (.., Some(a)) => bar(a), - | ^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:119:9 + --> tests/ui/match_same_arms2.rs:120:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), - | ----------------^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | help: try merging the arm patterns: `(Ok(x), Some(_)) | (Ok(_), Some(x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:120:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - (Ok(_), Some(x)) => println!("ok {}", x), | -LL | (Ok(_), Some(x)) => println!("ok {}", x), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:135:9 + --> tests/ui/match_same_arms2.rs:136:9 | LL | Ok(_) => println!("ok"), - | -----^^^^^^^^^^^^^^^^^^ - | | - | help: try merging the arm patterns: `Ok(_) | Ok(3)` + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:134:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | Ok(_) | Ok(3) => println!("ok"), + | ~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - Ok(3) => println!("ok"), | -LL | Ok(3) => println!("ok"), - | ^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:162:9 + --> tests/ui/match_same_arms2.rs:163:9 | -LL | 1 => { - | ^ help: try merging the arm patterns: `1 | 0` - | _________| - | | +LL | / 1 => { LL | | empty!(0); LL | | }, | |_________^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:159:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 1 | 0 => { + | ~~~~~ +help: and remove this obsolete arm + | +LL - 0 => { +LL - empty!(0); +LL - }, | -LL | / 0 => { -LL | | empty!(0); -LL | | }, - | |_________^ - -error: match expression looks like `matches!` macro - --> tests/ui/match_same_arms2.rs:181:16 - | -LL | let _ans = match x { - | ________________^ -LL | | E::A => false, -LL | | E::B => false, -LL | | _ => true, -LL | | }; - | |_____^ help: try: `!matches!(x, E::A | E::B)` - | - = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]` error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:213:9 + --> tests/ui/match_same_arms2.rs:214:9 | LL | Foo::X(0) => 1, - | ---------^^^^^ - | | - | help: try merging the arm patterns: `Foo::X(0) | Foo::Z(_)` + | ^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:215:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | Foo::X(0) | Foo::Z(_) => 1, + | ~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - Foo::Z(_) => 1, | -LL | Foo::Z(_) => 1, - | ^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:223:9 + --> tests/ui/match_same_arms2.rs:224:9 | LL | Foo::Z(_) => 1, - | ---------^^^^^ - | | - | help: try merging the arm patterns: `Foo::Z(_) | Foo::X(0)` + | ^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:221:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | Foo::Z(_) | Foo::X(0) => 1, + | ~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - Foo::X(0) => 1, | -LL | Foo::X(0) => 1, - | ^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:246:9 + --> tests/ui/match_same_arms2.rs:247:9 | LL | Some(Bar { y: 0, x: 5, .. }) => 1, - | ----------------------------^^^^^ - | | - | help: try merging the arm patterns: `Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:243:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - Some(Bar { x: 0, y: 5, .. }) => 1, | -LL | Some(Bar { x: 0, y: 5, .. }) => 1, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:260:9 + --> tests/ui/match_same_arms2.rs:261:9 | LL | 1 => cfg!(not_enable), - | -^^^^^^^^^^^^^^^^^^^^ - | | - | help: try merging the arm patterns: `1 | 0` + | ^^^^^^^^^^^^^^^^^^^^^ | - = help: or try changing either arm body -note: other arm here - --> tests/ui/match_same_arms2.rs:259:9 + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | 1 | 0 => cfg!(not_enable), + | ~~~~~ +help: and remove this obsolete arm + | +LL - 0 => cfg!(not_enable), | -LL | 0 => cfg!(not_enable), - | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed new file mode 100644 index 00000000000..804c0a869a9 --- /dev/null +++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed @@ -0,0 +1,61 @@ +#![feature(non_exhaustive_omitted_patterns_lint)] +#![warn(clippy::match_same_arms)] +#![no_main] +use std::sync::atomic::Ordering; // #[non_exhaustive] enum + +fn repeat() -> ! { + panic!() +} + +pub fn f(x: Ordering) { + #[deny(non_exhaustive_omitted_patterns)] + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel | Ordering::SeqCst => repeat(), + _ => repeat(), + } +} + +mod f { + #![deny(non_exhaustive_omitted_patterns)] + + use super::*; + + pub fn f(x: Ordering) { + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel | Ordering::SeqCst => repeat(), + _ => repeat(), + } + } +} + +// Below should still lint + +pub fn g(x: Ordering) { + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + //~^ ERROR: this match arm has an identical body to the `_` wildcard arm + _ => repeat(), + } +} + +mod g { + use super::*; + + pub fn g(x: Ordering) { + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + //~^ ERROR: this match arm has an identical body to the `_` wildcard arm + _ => repeat(), + } + } +} diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs index 5c277f925a8..e50663932a1 100644 --- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs +++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs @@ -1,7 +1,6 @@ #![feature(non_exhaustive_omitted_patterns_lint)] #![warn(clippy::match_same_arms)] #![no_main] -//@no-rustfix use std::sync::atomic::Ordering; // #[non_exhaustive] enum fn repeat() -> ! { diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr index cf2a75354e1..aa7f8c95dce 100644 --- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr @@ -1,12 +1,13 @@ error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms_non_exhaustive.rs:45:9 + --> tests/ui/match_same_arms_non_exhaustive.rs:44:9 | -LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm +LL | / Ordering::AcqRel | Ordering::SeqCst => repeat(), +LL | | + | |________^ help: try removing the arm | = help: or try changing either arm body note: `_` wildcard arm here - --> tests/ui/match_same_arms_non_exhaustive.rs:47:9 + --> tests/ui/match_same_arms_non_exhaustive.rs:46:9 | LL | _ => repeat(), | ^^^^^^^^^^^^^ @@ -14,14 +15,15 @@ LL | _ => repeat(), = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms_non_exhaustive.rs:59:13 + --> tests/ui/match_same_arms_non_exhaustive.rs:58:13 | -LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm +LL | / Ordering::AcqRel | Ordering::SeqCst => repeat(), +LL | | + | |____________^ help: try removing the arm | = help: or try changing either arm body note: `_` wildcard arm here - --> tests/ui/match_same_arms_non_exhaustive.rs:61:13 + --> tests/ui/match_same_arms_non_exhaustive.rs:60:13 | LL | _ => repeat(), | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index d026e009684..2750e0cdf3f 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -161,7 +161,23 @@ union U { f: u32, } -// Do not lint because accessing union fields from const functions is unstable +// Do not lint because accessing union fields from const functions is unstable in 1.55 +#[clippy::msrv = "1.55"] fn h(u: U) -> u32 { unsafe { u.f } } + +mod msrv { + struct Foo(*const u8, *mut u8); + + impl Foo { + #[clippy::msrv = "1.57"] + fn deref_ptr_cannot_be_const(self) -> usize { + unsafe { *self.0 as usize } + } + #[clippy::msrv = "1.58"] + fn deref_mut_ptr_cannot_be_const(self) -> usize { + unsafe { *self.1 as usize } + } + } +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs index 12a8320c8f3..06dbbeb31c0 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs @@ -113,3 +113,31 @@ impl const Drop for D { // Lint this, since it can be dropped in const contexts // FIXME(effects) fn d(this: D) {} + +mod msrv { + struct Foo(*const u8, &'static u8); + + impl Foo { + #[clippy::msrv = "1.58"] + fn deref_ptr_can_be_const(self) -> usize { + //~^ ERROR: this could be a `const fn` + unsafe { *self.0 as usize } + } + + fn deref_copied_val(self) -> usize { + //~^ ERROR: this could be a `const fn` + *self.1 as usize + } + } + + union Bar { + val: u8, + } + + #[clippy::msrv = "1.56"] + fn union_access_can_be_const() { + //~^ ERROR: this could be a `const fn` + let bar = Bar { val: 1 }; + let _ = unsafe { bar.val }; + } +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index 082459fd821..b2cade30563 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -102,5 +102,33 @@ LL | | 46 LL | | } | |_^ -error: aborting due to 11 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:122:9 + | +LL | / fn deref_ptr_can_be_const(self) -> usize { +LL | | +LL | | unsafe { *self.0 as usize } +LL | | } + | |_________^ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:127:9 + | +LL | / fn deref_copied_val(self) -> usize { +LL | | +LL | | *self.1 as usize +LL | | } + | |_________^ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:138:5 + | +LL | / fn union_access_can_be_const() { +LL | | +LL | | let bar = Bar { val: 1 }; +LL | | let _ = unsafe { bar.val }; +LL | | } + | |_____^ + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs index 0e1533fc1ab..b0fa8e98859 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.rs +++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs @@ -191,3 +191,11 @@ fn from_declared_macro_should_lint_at_macrosite() { // Not here. some_macro_that_panics!() } + +pub fn issue_12760<const N: usize>() { + const { + if N == 0 { + panic!(); + } + } +} diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed index bd7a9a0b984..5478372cbe0 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed @@ -141,8 +141,8 @@ fn main() { let f = |arg| { let loc = "loc".to_owned(); let _ = std::fs::write("x", &env); // Don't lint. In environment - let _ = std::fs::write("x", arg); - let _ = std::fs::write("x", loc); + let _ = std::fs::write("x", &arg); + let _ = std::fs::write("x", &loc); }; let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f` f(arg); @@ -158,13 +158,13 @@ fn main() { fn f(_: impl Debug) {} let x = X; - f(&x); // Don't lint. Has significant drop + f(&x); // Don't lint, not copy, passed by a reference to a variable } { fn f(_: impl AsRef<str>) {} let x = String::new(); - f(x); + f(&x); } { fn f(_: impl AsRef<str>) {} @@ -299,4 +299,38 @@ fn main() { check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop } } + { + #[derive(Debug)] + struct X(Vec<u8>); + + fn f(_: impl Debug) {} + + let x = X(vec![]); + f(&x); // Don't lint, makes x unavailable later + } + { + #[derive(Debug)] + struct X; + + impl Drop for X { + fn drop(&mut self) {} + } + + fn f(_: impl Debug) {} + + #[derive(Debug)] + struct Y(X); + + let y = Y(X); + f(&y); // Don't lint. Not copy, passed by a reference to value + } + { + fn f(_: impl AsRef<str>) {} + let x = String::new(); + f(&x); // Don't lint, not a copy, makes it unavailable later + f(String::new()); // Lint, makes no difference + let y = "".to_owned(); + f(&y); // Don't lint + f("".to_owned()); // Lint + } } diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs index 5cfd4ce30cc..2643815d939 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs @@ -158,7 +158,7 @@ fn main() { fn f(_: impl Debug) {} let x = X; - f(&x); // Don't lint. Has significant drop + f(&x); // Don't lint, not copy, passed by a reference to a variable } { fn f(_: impl AsRef<str>) {} @@ -299,4 +299,38 @@ fn main() { check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop } } + { + #[derive(Debug)] + struct X(Vec<u8>); + + fn f(_: impl Debug) {} + + let x = X(vec![]); + f(&x); // Don't lint, makes x unavailable later + } + { + #[derive(Debug)] + struct X; + + impl Drop for X { + fn drop(&mut self) {} + } + + fn f(_: impl Debug) {} + + #[derive(Debug)] + struct Y(X); + + let y = Y(X); + f(&y); // Don't lint. Not copy, passed by a reference to value + } + { + fn f(_: impl AsRef<str>) {} + let x = String::new(); + f(&x); // Don't lint, not a copy, makes it unavailable later + f(&String::new()); // Lint, makes no difference + let y = "".to_owned(); + f(&y); // Don't lint + f(&"".to_owned()); // Lint + } } diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr index 83c076f8d86..fba0755d14b 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr @@ -50,28 +50,22 @@ LL | let _ = Command::new("ls").args(&["-a", "-l"]).status().unwrap(); | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:144:41 - | -LL | let _ = std::fs::write("x", &arg); - | ^^^^ help: change this to: `arg` - -error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:145:41 + --> tests/ui/needless_borrows_for_generic_args.rs:247:13 | -LL | let _ = std::fs::write("x", &loc); - | ^^^^ help: change this to: `loc` +LL | foo(&a); + | ^^ help: change this to: `a` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:167:11 + --> tests/ui/needless_borrows_for_generic_args.rs:331:11 | -LL | f(&x); - | ^^ help: change this to: `x` +LL | f(&String::new()); // Lint, makes no difference + | ^^^^^^^^^^^^^^ help: change this to: `String::new()` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:247:13 + --> tests/ui/needless_borrows_for_generic_args.rs:334:11 | -LL | foo(&a); - | ^^ help: change this to: `a` +LL | f(&"".to_owned()); // Lint + | ^^^^^^^^^^^^^^ help: change this to: `"".to_owned()` -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index 1695784030d..ce64861fa40 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -8,10 +8,11 @@ LL | a = "zero"; | = note: `-D clippy::needless-late-init` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_late_init)]` -help: declare `a` here +help: move the declaration `a` here + | +LL ~ +LL ~ let a = "zero"; | -LL | let a = "zero"; - | ~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:30:5 @@ -22,10 +23,12 @@ LL | let c; LL | b = 1; | ^^^^^ initialised here | -help: declare `b` here +help: move the declaration `b` here + | +LL ~ +LL | let c; +LL ~ let b = 1; | -LL | let b = 1; - | ~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:31:5 @@ -36,10 +39,12 @@ LL | b = 1; LL | c = 2; | ^^^^^ initialised here | -help: declare `c` here +help: move the declaration `c` here + | +LL ~ +LL | b = 1; +LL ~ let c = 2; | -LL | let c = 2; - | ~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:35:5 @@ -49,10 +54,11 @@ LL | let d: usize; LL | d = 1; | ^^^^^ initialised here | -help: declare `d` here +help: move the declaration `d` here + | +LL ~ +LL ~ let d: usize = 1; | -LL | let d: usize = 1; - | ~~~~~~~~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:38:5 @@ -62,10 +68,11 @@ LL | let e; LL | e = format!("{}", d); | ^^^^^^^^^^^^^^^^^^^^ initialised here | -help: declare `e` here +help: move the declaration `e` here + | +LL ~ +LL ~ let e = format!("{}", d); | -LL | let e = format!("{}", d); - | ~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:43:5 @@ -73,20 +80,17 @@ error: unneeded late initialization LL | let a; | ^^^^^^ | -help: declare `a` here - | -LL | let a = match n { - | +++++++ -help: remove the assignments from the `match` arms +help: move the declaration `a` here and remove the assignments from the `match` arms | +LL ~ +LL | let n = 1; +LL ~ let a = match n { LL ~ 1 => "one", LL | _ => { LL ~ "two" +LL | }, +LL ~ }; | -help: add a semicolon after the `match` expression - | -LL | }; - | + error: unneeded late initialization --> tests/ui/needless_late_init.rs:52:5 @@ -94,20 +98,15 @@ error: unneeded late initialization LL | let b; | ^^^^^^ | -help: declare `b` here - | -LL | let b = if n == 3 { - | +++++++ -help: remove the assignments from the branches +help: move the declaration `b` here and remove the assignments from the branches | +LL ~ +LL ~ let b = if n == 3 { LL ~ "four" LL | } else { LL ~ "five" +LL ~ }; | -help: add a semicolon after the `if` expression - | -LL | }; - | + error: unneeded late initialization --> tests/ui/needless_late_init.rs:59:5 @@ -115,20 +114,16 @@ error: unneeded late initialization LL | let d; | ^^^^^^ | -help: declare `d` here - | -LL | let d = if true { - | +++++++ -help: remove the assignments from the branches +help: move the declaration `d` here and remove the assignments from the branches | +LL ~ +LL ~ let d = if true { +LL | let temp = 5; LL ~ temp LL | } else { LL ~ 15 +LL ~ }; | -help: add a semicolon after the `if` expression - | -LL | }; - | + error: unneeded late initialization --> tests/ui/needless_late_init.rs:67:5 @@ -136,20 +131,15 @@ error: unneeded late initialization LL | let e; | ^^^^^^ | -help: declare `e` here - | -LL | let e = if true { - | +++++++ -help: remove the assignments from the branches +help: move the declaration `e` here and remove the assignments from the branches | +LL ~ +LL ~ let e = if true { LL ~ format!("{} {}", a, b) LL | } else { LL ~ format!("{}", n) +LL ~ }; | -help: add a semicolon after the `if` expression - | -LL | }; - | + error: unneeded late initialization --> tests/ui/needless_late_init.rs:74:5 @@ -157,14 +147,11 @@ error: unneeded late initialization LL | let f; | ^^^^^^ | -help: declare `f` here - | -LL | let f = match 1 { - | +++++++ -help: remove the assignments from the `match` arms +help: move the declaration `f` here and remove the assignments from the `match` arms | -LL - 1 => f = "three", -LL + 1 => "three", +LL ~ +LL ~ let f = match 1 { +LL ~ 1 => "three", | error: unneeded late initialization @@ -173,19 +160,15 @@ error: unneeded late initialization LL | let g: usize; | ^^^^^^^^^^^^^ | -help: declare `g` here - | -LL | let g: usize = if true { - | ++++++++++++++ -help: remove the assignments from the branches - | -LL - g = 5; -LL + 5 +help: move the declaration `g` here and remove the assignments from the branches | -help: add a semicolon after the `if` expression +LL ~ +LL ~ let g: usize = if true { +LL ~ 5 +LL | } else { +LL | panic!(); +LL ~ }; | -LL | }; - | + error: unneeded late initialization --> tests/ui/needless_late_init.rs:88:5 @@ -196,10 +179,12 @@ LL | let y = SignificantDrop; LL | x = 1; | ^^^^^ initialised here | -help: declare `x` here +help: move the declaration `x` here + | +LL ~ +LL | let y = SignificantDrop; +LL ~ let x = 1; | -LL | let x = 1; - | ~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:92:5 @@ -210,10 +195,12 @@ LL | let y = 1; LL | x = SignificantDrop; | ^^^^^^^^^^^^^^^^^^^ initialised here | -help: declare `x` here +help: move the declaration `x` here + | +LL ~ +LL | let y = 1; +LL ~ let x = SignificantDrop; | -LL | let x = SignificantDrop; - | ~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:96:5 @@ -224,10 +211,14 @@ LL | let x; LL | x = SignificantDrop; | ^^^^^^^^^^^^^^^^^^^ initialised here | -help: declare `x` here +help: move the declaration `x` here + | +LL ~ +LL | // types that should be considered insignificant + ... +LL | let y = Box::new(4); +LL ~ let x = SignificantDrop; | -LL | let x = SignificantDrop; - | ~~~~~ error: unneeded late initialization --> tests/ui/needless_late_init.rs:115:5 @@ -235,20 +226,17 @@ error: unneeded late initialization LL | let a; | ^^^^^^ | -help: declare `a` here - | -LL | let a = match n { - | +++++++ -help: remove the assignments from the `match` arms +help: move the declaration `a` here and remove the assignments from the `match` arms | +LL ~ +LL | let n = 1; +LL ~ let a = match n { LL ~ 1 => f().await, LL | _ => { LL ~ "two" +LL | }, +LL ~ }; | -help: add a semicolon after the `match` expression - | -LL | }; - | + error: unneeded late initialization --> tests/ui/needless_late_init.rs:132:5 @@ -256,20 +244,17 @@ error: unneeded late initialization LL | let a; | ^^^^^^ | -help: declare `a` here - | -LL | let a = match n { - | +++++++ -help: remove the assignments from the `match` arms +help: move the declaration `a` here and remove the assignments from the `match` arms | +LL ~ +LL | let n = 1; +LL ~ let a = match n { LL ~ 1 => f(), LL | _ => { LL ~ "two" +LL | }, +LL ~ }; | -help: add a semicolon after the `match` expression - | -LL | }; - | + error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index dabeda72f0c..0ea911c3434 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -1,6 +1,5 @@ #![feature(fn_traits, unboxed_closures)] #![warn(clippy::no_effect_underscore_binding)] -#![allow(dead_code, path_statements)] #![allow( clippy::deref_addrof, clippy::redundant_field_names, @@ -33,7 +32,6 @@ impl Neg for Cout { } } -struct Unit; struct Tuple(i32); struct Struct { field: i32, @@ -42,10 +40,6 @@ enum Enum { Tuple(i32), Struct { field: i32 }, } -struct DropUnit; -impl Drop for DropUnit { - fn drop(&mut self) {} -} struct DropStruct { field: i32, } @@ -117,15 +111,9 @@ impl FnOnce<(&str,)> for GreetStruct3 { fn main() { let s = get_struct(); - let s2 = get_struct(); 0; //~^ ERROR: statement with no effect - //~| NOTE: `-D clippy::no-effect` implied by `-D warnings` - s2; - //~^ ERROR: statement with no effect - Unit; - //~^ ERROR: statement with no effect Tuple(0); //~^ ERROR: statement with no effect Struct { field: 0 }; @@ -192,7 +180,6 @@ fn main() { unsafe { unsafe_fn() }; let _used = get_struct(); let _x = vec![1]; - DropUnit; DropStruct { field: 0 }; DropTuple(0); DropEnum::Tuple(0); diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr index c7c8eecd054..48ec997d938 100644 --- a/src/tools/clippy/tests/ui/no_effect.stderr +++ b/src/tools/clippy/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> tests/ui/no_effect.rs:122:5 + --> tests/ui/no_effect.rs:115:5 | LL | 0; | ^^ @@ -8,151 +8,139 @@ LL | 0; = help: to override `-D warnings` add `#[allow(clippy::no_effect)]` error: statement with no effect - --> tests/ui/no_effect.rs:125:5 - | -LL | s2; - | ^^^ - -error: statement with no effect - --> tests/ui/no_effect.rs:127:5 - | -LL | Unit; - | ^^^^^ - -error: statement with no effect - --> tests/ui/no_effect.rs:129:5 + --> tests/ui/no_effect.rs:117:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:131:5 + --> tests/ui/no_effect.rs:119:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:133:5 + --> tests/ui/no_effect.rs:121:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:135:5 + --> tests/ui/no_effect.rs:123:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:137:5 + --> tests/ui/no_effect.rs:125:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:139:5 + --> tests/ui/no_effect.rs:127:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:141:5 + --> tests/ui/no_effect.rs:129:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:143:5 + --> tests/ui/no_effect.rs:131:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:145:5 + --> tests/ui/no_effect.rs:133:5 | LL | &6; | ^^^ error: statement with no effect - --> tests/ui/no_effect.rs:147:5 + --> tests/ui/no_effect.rs:135:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:149:5 + --> tests/ui/no_effect.rs:137:5 | LL | ..; | ^^^ error: statement with no effect - --> tests/ui/no_effect.rs:151:5 + --> tests/ui/no_effect.rs:139:5 | LL | 5..; | ^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:153:5 + --> tests/ui/no_effect.rs:141:5 | LL | ..5; | ^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:155:5 + --> tests/ui/no_effect.rs:143:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:157:5 + --> tests/ui/no_effect.rs:145:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:159:5 + --> tests/ui/no_effect.rs:147:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:161:5 + --> tests/ui/no_effect.rs:149:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:163:5 + --> tests/ui/no_effect.rs:151:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:165:5 + --> tests/ui/no_effect.rs:153:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:167:5 + --> tests/ui/no_effect.rs:155:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:170:5 + --> tests/ui/no_effect.rs:158:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:173:5 + --> tests/ui/no_effect.rs:161:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:175:9 + --> tests/ui/no_effect.rs:163:9 | LL | let _unused = 1; | ^^^^^^^ @@ -161,22 +149,22 @@ LL | let _unused = 1; = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:178:9 + --> tests/ui/no_effect.rs:166:9 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:180:9 + --> tests/ui/no_effect.rs:168:9 | LL | let _duck = Struct { field: 0 }; | ^^^^^ error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:182:9 + --> tests/ui/no_effect.rs:170:9 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^ -error: aborting due to 29 previous errors +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs index 0305d895fc5..7fc89bb9538 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs @@ -675,4 +675,60 @@ fn should_not_trigger_on_significant_iterator_drop() { } } +// https://github.com/rust-lang/rust-clippy/issues/9072 +fn should_not_trigger_lint_if_place_expr_has_significant_drop() { + let x = Mutex::new(vec![1, 2, 3]); + let x_guard = x.lock().unwrap(); + + match x_guard[0] { + 1 => println!("1!"), + x => println!("{x}"), + } + + match x_guard.len() { + 1 => println!("1!"), + x => println!("{x}"), + } +} + +struct Guard<'a, T>(MutexGuard<'a, T>); + +struct Ref<'a, T>(&'a T); + +impl<'a, T> Guard<'a, T> { + fn guard(&self) -> &MutexGuard<T> { + &self.0 + } + + fn guard_ref(&self) -> Ref<MutexGuard<T>> { + Ref(&self.0) + } + + fn take(self) -> Box<MutexGuard<'a, T>> { + Box::new(self.0) + } +} + +fn should_not_trigger_for_significant_drop_ref() { + let mutex = Mutex::new(vec![1, 2]); + let guard = Guard(mutex.lock().unwrap()); + + match guard.guard().len() { + 0 => println!("empty"), + _ => println!("not empty"), + } + + match guard.guard_ref().0.len() { + 0 => println!("empty"), + _ => println!("not empty"), + } + + match guard.take().len() { + //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + 0 => println!("empty"), + _ => println!("not empty"), + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr index 7d5b1acc7f0..811bb065527 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr @@ -28,6 +28,9 @@ LL | match s.lock_m().get_the_value() { LL | println!("{}", s.lock_m().get_the_value()); | ---------- another value with significant `Drop` created here ... +LL | println!("{}", s.lock_m().get_the_value()); + | ---------- another value with significant `Drop` created here +... LL | } | - temporary lives until here | @@ -47,6 +50,9 @@ LL | match s.lock_m_m().get_the_value() { LL | println!("{}", s.lock_m().get_the_value()); | ---------- another value with significant `Drop` created here ... +LL | println!("{}", s.lock_m().get_the_value()); + | ---------- another value with significant `Drop` created here +... LL | } | - temporary lives until here | @@ -360,7 +366,7 @@ LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | _ => println!("Value is {}", s.lock().deref()), - | ---------------- another value with significant `Drop` created here + | -------- another value with significant `Drop` created here LL | }; | - temporary lives until here | @@ -378,7 +384,7 @@ LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | matcher => println!("Value is {}", s.lock().deref()), - | ---------------- another value with significant `Drop` created here + | -------- another value with significant `Drop` created here LL | _ => println!("Value was not a match"), LL | }; | - temporary lives until here @@ -499,5 +505,21 @@ LL ~ let value = mutex.lock().unwrap().foo(); LL ~ match value { | -error: aborting due to 26 previous errors +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> tests/ui/significant_drop_in_scrutinee.rs:726:11 + | +LL | match guard.take().len() { + | ^^^^^^^^^^^^^^^^^^ +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = guard.take().len(); +LL ~ match value { + | + +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed index ad0e5fab029..2c582c90ba8 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed @@ -21,6 +21,8 @@ fn main() { let _ = check_files_ref_mut(&[(FileType::Account, path)]); let _ = check_files_self_and_arg(&[(FileType::Account, path)]); let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); + + check_mut_iteratee_and_modify_inner_variable(); } // `check_files` and its variants are based on: @@ -138,3 +140,33 @@ fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> { Ok(std::path::PathBuf::new()) } + +// Issue 12098 +// https://github.com/rust-lang/rust-clippy/issues/12098 +// no message emits +fn check_mut_iteratee_and_modify_inner_variable() { + struct Test { + list: Vec<String>, + mut_this: bool, + } + + impl Test { + fn list(&self) -> &[String] { + &self.list + } + } + + let mut test = Test { + list: vec![String::from("foo"), String::from("bar")], + mut_this: false, + }; + + for _item in test.list().to_vec() { + println!("{}", _item); + + test.mut_this = true; + { + test.mut_this = true; + } + } +} diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs index d3d59c4c70f..a28ccd1efef 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs @@ -21,6 +21,8 @@ fn main() { let _ = check_files_ref_mut(&[(FileType::Account, path)]); let _ = check_files_self_and_arg(&[(FileType::Account, path)]); let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); + + check_mut_iteratee_and_modify_inner_variable(); } // `check_files` and its variants are based on: @@ -138,3 +140,33 @@ fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> { Ok(std::path::PathBuf::new()) } + +// Issue 12098 +// https://github.com/rust-lang/rust-clippy/issues/12098 +// no message emits +fn check_mut_iteratee_and_modify_inner_variable() { + struct Test { + list: Vec<String>, + mut_this: bool, + } + + impl Test { + fn list(&self) -> &[String] { + &self.list + } + } + + let mut test = Test { + list: vec![String::from("foo"), String::from("bar")], + mut_this: false, + }; + + for _item in test.list().to_vec() { + println!("{}", _item); + + test.mut_this = true; + { + test.mut_this = true; + } + } +} diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr index 9d3591e0dbf..fb98cfddc26 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr @@ -1,5 +1,5 @@ error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:29:22 + --> tests/ui/unnecessary_iter_cloned.rs:31:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL + let other = match get_file_path(t) { | error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:44:22 + --> tests/ui/unnecessary_iter_cloned.rs:46:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed index 81759086f79..231fc0a892a 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.fixed +++ b/src/tools/clippy/tests/ui/useless_attribute.fixed @@ -86,8 +86,51 @@ mod module { #[rustfmt::skip] #[allow(unused_import_braces)] +#[allow(unused_braces)] use module::{Struct}; fn main() { test_indented_attr(); } + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/4467 +#[allow(dead_code)] +use std::collections as puppy_doggy; + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/11595 +pub mod hidden_glob_reexports { + #![allow(unreachable_pub)] + + mod my_prelude { + pub struct MyCoolTypeInternal; + pub use MyCoolTypeInternal as MyCoolType; + } + + mod my_uncool_type { + pub(crate) struct MyUncoolType; + } + + // This exports `MyCoolType`. + pub use my_prelude::*; + + // This hides `my_prelude::MyCoolType`. + #[allow(hidden_glob_reexports)] + use my_uncool_type::MyUncoolType as MyCoolType; +} + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/10878 +pub mod ambiguous_glob_exports { + #![allow(unreachable_pub)] + + mod my_prelude { + pub struct MyType; + } + + mod my_type { + pub struct MyType; + } + + #[allow(ambiguous_glob_reexports)] + pub use my_prelude::*; + pub use my_type::*; +} diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs index 59a9dcf093b..8dfcd2110a4 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.rs +++ b/src/tools/clippy/tests/ui/useless_attribute.rs @@ -86,8 +86,51 @@ mod module { #[rustfmt::skip] #[allow(unused_import_braces)] +#[allow(unused_braces)] use module::{Struct}; fn main() { test_indented_attr(); } + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/4467 +#[allow(dead_code)] +use std::collections as puppy_doggy; + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/11595 +pub mod hidden_glob_reexports { + #![allow(unreachable_pub)] + + mod my_prelude { + pub struct MyCoolTypeInternal; + pub use MyCoolTypeInternal as MyCoolType; + } + + mod my_uncool_type { + pub(crate) struct MyUncoolType; + } + + // This exports `MyCoolType`. + pub use my_prelude::*; + + // This hides `my_prelude::MyCoolType`. + #[allow(hidden_glob_reexports)] + use my_uncool_type::MyUncoolType as MyCoolType; +} + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/10878 +pub mod ambiguous_glob_exports { + #![allow(unreachable_pub)] + + mod my_prelude { + pub struct MyType; + } + + mod my_type { + pub struct MyType; + } + + #[allow(ambiguous_glob_reexports)] + pub use my_prelude::*; + pub use my_type::*; +} diff --git a/src/tools/clippy/tests/ui/while_float.rs b/src/tools/clippy/tests/ui/while_float.rs new file mode 100644 index 00000000000..a3b0618948e --- /dev/null +++ b/src/tools/clippy/tests/ui/while_float.rs @@ -0,0 +1,14 @@ +#[deny(clippy::while_float)] +fn main() { + let mut x = 0.0_f32; + while x < 42.0_f32 { + x += 0.5; + } + while x < 42.0 { + x += 1.0; + } + let mut x = 0; + while x < 42 { + x += 1; + } +} diff --git a/src/tools/clippy/tests/ui/while_float.stderr b/src/tools/clippy/tests/ui/while_float.stderr new file mode 100644 index 00000000000..b8e934b97c6 --- /dev/null +++ b/src/tools/clippy/tests/ui/while_float.stderr @@ -0,0 +1,20 @@ +error: while condition comparing floats + --> tests/ui/while_float.rs:4:11 + | +LL | while x < 42.0_f32 { + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/while_float.rs:1:8 + | +LL | #[deny(clippy::while_float)] + | ^^^^^^^^^^^^^^^^^^^ + +error: while condition comparing floats + --> tests/ui/while_float.rs:7:11 + | +LL | while x < 42.0 { + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index c63edd5bf70..7fd779fe9a4 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -406,7 +406,7 @@ } // Search by id - if (lint.id.indexOf(searchStr.replace("-", "_")) !== -1) { + if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) { return true; } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 3f4fceccab0..96fb8e27e6d 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -234,7 +234,6 @@ run-make/rmeta-preferred/Makefile run-make/rustc-macro-dep-files/Makefile run-make/rustdoc-io-error/Makefile run-make/rustdoc-scrape-examples-macros/Makefile -run-make/rustdoc-scrape-examples-multiple/Makefile run-make/rustdoc-verify-output-files/Makefile run-make/rustdoc-with-output-option/Makefile run-make/rustdoc-with-short-out-dir-option/Makefile diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 6e92dab1abc..e1c6c9a2dac 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -16,7 +16,7 @@ const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1676; -const ROOT_ENTRY_LIMIT: usize = 859; +const ROOT_ENTRY_LIMIT: usize = 757; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/Makefile b/tests/run-make/rustdoc-scrape-examples-multiple/Makefile deleted file mode 100644 index 453a7d4bc8b..00000000000 --- a/tests/run-make/rustdoc-scrape-examples-multiple/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -deps := ex ex2 - -include ./scrape.mk - -all: scrape diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs new file mode 100644 index 00000000000..e9c54fa3922 --- /dev/null +++ b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs @@ -0,0 +1,6 @@ +#[path = "../rustdoc-scrape-examples-remap/scrape.rs"] +mod scrape; + +fn main() { + scrape::scrape(&[]); +} diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk b/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk deleted file mode 100644 index 57220bc6635..00000000000 --- a/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk +++ /dev/null @@ -1,21 +0,0 @@ -include ../tools.mk - -OUTPUT_DIR := "$(TMPDIR)/rustdoc" - -$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta - $(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \ - --extern foobar=$(TMPDIR)/libfoobar.rmeta \ - -Z unstable-options \ - --scrape-examples-output-path $@ \ - --scrape-examples-target-crate foobar \ - $(extra_flags) - -$(TMPDIR)/lib%.rmeta: src/lib.rs - $(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata - -scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls) - $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \ - -Z unstable-options \ - $(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls) - - $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs diff --git a/tests/ui/empty_global_asm.rs b/tests/ui/asm/empty_global_asm.rs index 2517796ad10..2517796ad10 100644 --- a/tests/ui/empty_global_asm.rs +++ b/tests/ui/asm/empty_global_asm.rs diff --git a/tests/ui/simple_global_asm.rs b/tests/ui/asm/simple_global_asm.rs index 9b193b3e44c..9b193b3e44c 100644 --- a/tests/ui/simple_global_asm.rs +++ b/tests/ui/asm/simple_global_asm.rs diff --git a/tests/ui/backtrace-apple-no-dsymutil.rs b/tests/ui/backtrace/apple-no-dsymutil.rs index 9924cd13b0a..9924cd13b0a 100644 --- a/tests/ui/backtrace-apple-no-dsymutil.rs +++ b/tests/ui/backtrace/apple-no-dsymutil.rs diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs b/tests/ui/backtrace/auxiliary/dylib-dep-helper-aux.rs index d45e0bcd3b4..d45e0bcd3b4 100644 --- a/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs +++ b/tests/ui/backtrace/auxiliary/dylib-dep-helper-aux.rs diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs b/tests/ui/backtrace/auxiliary/dylib-dep-helper.rs index 565d8b65de0..565d8b65de0 100644 --- a/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs +++ b/tests/ui/backtrace/auxiliary/dylib-dep-helper.rs diff --git a/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs b/tests/ui/backtrace/auxiliary/line-tables-only-helper.rs index 65da2c3f5c7..65da2c3f5c7 100644 --- a/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs +++ b/tests/ui/backtrace/auxiliary/line-tables-only-helper.rs diff --git a/tests/ui/backtrace.rs b/tests/ui/backtrace/backtrace.rs index 2579ff5203b..2579ff5203b 100644 --- a/tests/ui/backtrace.rs +++ b/tests/ui/backtrace/backtrace.rs diff --git a/tests/ui/debuginfo/backtrace-dylib-dep.rs b/tests/ui/backtrace/dylib-dep.rs index fcd1f92e28e..fcd1f92e28e 100644 --- a/tests/ui/debuginfo/backtrace-dylib-dep.rs +++ b/tests/ui/backtrace/dylib-dep.rs diff --git a/tests/ui/debuginfo/backtrace-line-tables-only.rs b/tests/ui/backtrace/line-tables-only.rs index 044f59e483a..044f59e483a 100644 --- a/tests/ui/debuginfo/backtrace-line-tables-only.rs +++ b/tests/ui/backtrace/line-tables-only.rs diff --git a/tests/ui/std-backtrace.rs b/tests/ui/backtrace/std-backtrace.rs index b4806457877..b4806457877 100644 --- a/tests/ui/std-backtrace.rs +++ b/tests/ui/backtrace/std-backtrace.rs diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr index 75df314e0ba..82b2d7d1b1d 100644 --- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr +++ b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr @@ -1,4 +1,4 @@ -error: `crate_type` within an `#![cfg_attr] attribute is deprecated` +error: `crate_type` within an `#![cfg_attr]` attribute is deprecated --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18 | LL | #![cfg_attr(foo, crate_type="bin")] @@ -8,7 +8,7 @@ LL | #![cfg_attr(foo, crate_type="bin")] = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> = note: `#[deny(deprecated_cfg_attr_crate_type_name)]` on by default -error: `crate_name` within an `#![cfg_attr] attribute is deprecated` +error: `crate_name` within an `#![cfg_attr]` attribute is deprecated --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18 | LL | #![cfg_attr(foo, crate_name="bar")] @@ -17,7 +17,7 @@ LL | #![cfg_attr(foo, crate_name="bar")] = 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 #91632 <https://github.com/rust-lang/rust/issues/91632> -error: `crate_type` within an `#![cfg_attr] attribute is deprecated` +error: `crate_type` within an `#![cfg_attr]` attribute is deprecated --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18 | LL | #![cfg_attr(foo, crate_type="bin")] @@ -27,7 +27,7 @@ LL | #![cfg_attr(foo, crate_type="bin")] = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `crate_name` within an `#![cfg_attr] attribute is deprecated` +error: `crate_name` within an `#![cfg_attr]` attribute is deprecated --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18 | LL | #![cfg_attr(foo, crate_name="bar")] diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index ae4c1605f01..b311a80c8fd 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `FALSE` LL | #[cfg(FALSE)] | ^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(FALSE)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr index a940eda4689..9d3117ed54d 100644 --- a/tests/ui/check-cfg/cargo-feature.none.stderr +++ b/tests/ui/check-cfg/cargo-feature.none.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: consider using a Cargo feature instead = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: [lints.rust] diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr index 70d3182eec8..14e24cb1429 100644 --- a/tests/ui/check-cfg/cargo-feature.some.stderr +++ b/tests/ui/check-cfg/cargo-feature.some.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: consider using a Cargo feature instead = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: [lints.rust] diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr index 4975129802b..08bd43832ea 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `value` LL | #[cfg(value)] | ^^^^^ | - = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(value)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr index 6404556f46c..6db1144eada 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `my_value` LL | #[cfg(my_value)] | ^^^^^^^^ | - = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(my_value)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr index bda1a601410..a5f8176343a 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `linux` LL | #[cfg(linux)] | ^^^^^ help: found config with similar value: `target_os = "linux"` | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(linux)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index 079be8d08c2..6fecdb52362 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `target_architecture` LL | #[cfg(target(os = "linux", architecture = "arm"))] | ^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr index 4fe921dd24b..c8d14f8c02a 100644 --- a/tests/ui/check-cfg/compact-values.stderr +++ b/tests/ui/check-cfg/compact-values.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value: `X` LL | #[cfg(target(os = "linux", pointer_width = "X"))] | ^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_pointer_width` are: `16`, `32`, `64` + = note: expected values for `target_pointer_width` are: `16`, `32`, and `64` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr index a508c397661..ec740952f57 100644 --- a/tests/ui/check-cfg/concat-values.stderr +++ b/tests/ui/check-cfg/concat-values.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value: (none) LL | #[cfg(my_cfg)] | ^^^^^^ | - = note: expected values for `my_cfg` are: `bar`, `foo` + = note: expected values for `my_cfg` are: `bar` and `foo` = help: to expect this configuration use `--check-cfg=cfg(my_cfg)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default @@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `unk` LL | #[cfg(my_cfg = "unk")] | ^^^^^^^^^^^^^^ | - = note: expected values for `my_cfg` are: `bar`, `foo` + = note: expected values for `my_cfg` are: `bar` and `foo` = help: to expect this configuration use `--check-cfg=cfg(my_cfg, values("unk"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr index 755373d7b77..2497864e87e 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr index 6344739ae76..a7d4c6d4df6 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr index 6344739ae76..a7d4c6d4df6 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names.stderr b/tests/ui/check-cfg/exhaustive-names.stderr index 605825cd4e5..7ac3241db5f 100644 --- a/tests/ui/check-cfg/exhaustive-names.stderr +++ b/tests/ui/check-cfg/exhaustive-names.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 54591699145..8c1bf5a1160 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -44,7 +44,7 @@ warning: unexpected `cfg` condition name: `uu` LL | #[cfg_attr(uu, test)] | ^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(uu)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2` and 188 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, and `bmi2` and 188 more = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr index ab0deae428d..e8b61d808fe 100644 --- a/tests/ui/check-cfg/stmt-no-ice.stderr +++ b/tests/ui/check-cfg/stmt-no-ice.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `crossbeam_loom` LL | #[cfg(crossbeam_loom)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(crossbeam_loom)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/unexpected-cfg-value.stderr b/tests/ui/check-cfg/unexpected-cfg-value.stderr index efcf65bb707..0fa0dde41b6 100644 --- a/tests/ui/check-cfg/unexpected-cfg-value.stderr +++ b/tests/ui/check-cfg/unexpected-cfg-value.stderr @@ -6,7 +6,7 @@ LL | #[cfg(feature = "sedre")] | | | help: there is a expected value with a similar name: `"serde"` | - = note: expected values for `feature` are: `full`, `serde` + = note: expected values for `feature` are: `full` and `serde` = help: to expect this configuration use `--check-cfg=cfg(feature, values("sedre"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default @@ -17,7 +17,7 @@ warning: unexpected `cfg` condition value: `rand` LL | #[cfg(feature = "rand")] | ^^^^^^^^^^^^^^^^ | - = note: expected values for `feature` are: `full`, `serde` + = note: expected values for `feature` are: `full` and `serde` = help: to expect this configuration use `--check-cfg=cfg(feature, values("rand"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr index 2ce6fe80ef2..41130210df1 100644 --- a/tests/ui/check-cfg/well-known-names.stderr +++ b/tests/ui/check-cfg/well-known-names.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition name: `features` LL | #[cfg(features = "foo")] | ^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` = help: to expect this configuration use `--check-cfg=cfg(features, values("foo"))` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index db4a5fd49e6..c13446bb9f8 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -71,7 +71,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort`, `unwind` + = note: expected values for `panic` are: `abort` and `unwind` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -91,7 +91,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | relocation_model = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `relocation_model` are: `dynamic-no-pic`, `pic`, `pie`, `ropi`, `ropi-rwpi`, `rwpi`, `static` + = note: expected values for `relocation_model` are: `dynamic-no-pic`, `pic`, `pie`, `ropi`, `ropi-rwpi`, `rwpi`, and `static` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -111,7 +111,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread` + = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, and `thread` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -120,7 +120,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, `x32` + = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64` + = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, and `x86_64` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -138,7 +138,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_endian = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_endian` are: `big`, `little` + = note: expected values for `target_endian` are: `big` and `little` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -147,7 +147,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p2`, `psx`, `relibc`, `sgx`, `uclibc` + = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p2`, `psx`, `relibc`, `sgx`, and `uclibc` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_family = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_family` are: `unix`, `wasm`, `windows` + = note: expected values for `target_family` are: `unix`, `wasm`, and `windows` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_has_atomic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr` + = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -183,7 +183,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_has_atomic_equal_alignment` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr` + = note: expected values for `target_has_atomic_equal_alignment` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -192,7 +192,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_has_atomic_load_store` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr` + = note: expected values for `target_has_atomic_load_store` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -210,7 +210,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_pointer_width = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_pointer_width` are: `16`, `32`, `64` + = note: expected values for `target_pointer_width` are: `16`, `32`, and `64` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -230,7 +230,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, `wrs` + = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -285,7 +285,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: 29 warnings emitted diff --git a/tests/ui/auxiliary/orphan-check-diagnostics.rs b/tests/ui/coherence/auxiliary/orphan-check-diagnostics.rs index 6b2c42b69b9..6b2c42b69b9 100644 --- a/tests/ui/auxiliary/orphan-check-diagnostics.rs +++ b/tests/ui/coherence/auxiliary/orphan-check-diagnostics.rs diff --git a/tests/ui/orphan-check-diagnostics.rs b/tests/ui/coherence/orphan-check-diagnostics.rs index 4b6557fc9c8..4b6557fc9c8 100644 --- a/tests/ui/orphan-check-diagnostics.rs +++ b/tests/ui/coherence/orphan-check-diagnostics.rs diff --git a/tests/ui/orphan-check-diagnostics.stderr b/tests/ui/coherence/orphan-check-diagnostics.stderr index b9fa7baf4c2..b9fa7baf4c2 100644 --- a/tests/ui/orphan-check-diagnostics.stderr +++ b/tests/ui/coherence/orphan-check-diagnostics.stderr diff --git a/tests/ui/cross-crate/xcrate-address-insignificant.rs b/tests/ui/cross-crate/address-insignificant.rs index 891fe14d9a0..891fe14d9a0 100644 --- a/tests/ui/cross-crate/xcrate-address-insignificant.rs +++ b/tests/ui/cross-crate/address-insignificant.rs diff --git a/tests/ui/cross-crate/xcrate-associated-type-defaults.rs b/tests/ui/cross-crate/associated-type-defaults.rs index 04eb90afae9..04eb90afae9 100644 --- a/tests/ui/cross-crate/xcrate-associated-type-defaults.rs +++ b/tests/ui/cross-crate/associated-type-defaults.rs diff --git a/tests/ui/xcrate/auxiliary/static_priv_by_default.rs b/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs index 39f912066ec..39f912066ec 100644 --- a/tests/ui/xcrate/auxiliary/static_priv_by_default.rs +++ b/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs diff --git a/tests/ui/xcrate/auxiliary/xcrate_unit_struct.rs b/tests/ui/cross-crate/auxiliary/xcrate_unit_struct.rs index 4f8b3508398..4f8b3508398 100644 --- a/tests/ui/xcrate/auxiliary/xcrate_unit_struct.rs +++ b/tests/ui/cross-crate/auxiliary/xcrate_unit_struct.rs diff --git a/tests/ui/cross-crate/xcrate_generic_fn_nested_return.rs b/tests/ui/cross-crate/generic_fn_nested_return.rs index dbfcdf8197a..dbfcdf8197a 100644 --- a/tests/ui/cross-crate/xcrate_generic_fn_nested_return.rs +++ b/tests/ui/cross-crate/generic_fn_nested_return.rs diff --git a/tests/ui/xcrate/xcrate-private-by-default.rs b/tests/ui/cross-crate/private-by-default.rs index 3a5d8131344..3a5d8131344 100644 --- a/tests/ui/xcrate/xcrate-private-by-default.rs +++ b/tests/ui/cross-crate/private-by-default.rs diff --git a/tests/ui/xcrate/xcrate-private-by-default.stderr b/tests/ui/cross-crate/private-by-default.stderr index 25bbbf5f62a..398c9088aae 100644 --- a/tests/ui/xcrate/xcrate-private-by-default.stderr +++ b/tests/ui/cross-crate/private-by-default.stderr @@ -1,5 +1,5 @@ error[E0603]: static `j` is private - --> $DIR/xcrate-private-by-default.rs:23:29 + --> $DIR/private-by-default.rs:23:29 | LL | static_priv_by_default::j; | ^ private static @@ -11,7 +11,7 @@ LL | static j: isize = 0; | ^^^^^^^^^^^^^^^ error[E0603]: function `k` is private - --> $DIR/xcrate-private-by-default.rs:25:29 + --> $DIR/private-by-default.rs:25:29 | LL | static_priv_by_default::k; | ^ private function @@ -23,7 +23,7 @@ LL | fn k() {} | ^^^^^^ error[E0603]: unit struct `l` is private - --> $DIR/xcrate-private-by-default.rs:27:29 + --> $DIR/private-by-default.rs:27:29 | LL | static_priv_by_default::l; | ^ private unit struct @@ -35,7 +35,7 @@ LL | struct l; | ^^^^^^^^ error[E0603]: enum `m` is private - --> $DIR/xcrate-private-by-default.rs:29:35 + --> $DIR/private-by-default.rs:29:35 | LL | foo::<static_priv_by_default::m>(); | ^ private enum @@ -47,7 +47,7 @@ LL | enum m {} | ^^^^^^ error[E0603]: type alias `n` is private - --> $DIR/xcrate-private-by-default.rs:31:35 + --> $DIR/private-by-default.rs:31:35 | LL | foo::<static_priv_by_default::n>(); | ^ private type alias @@ -59,7 +59,7 @@ LL | type n = isize; | ^^^^^^ error[E0603]: module `foo` is private - --> $DIR/xcrate-private-by-default.rs:35:29 + --> $DIR/private-by-default.rs:35:29 | LL | static_priv_by_default::foo::a; | ^^^ - static `a` is not publicly re-exported @@ -73,7 +73,7 @@ LL | mod foo { | ^^^^^^^ error[E0603]: module `foo` is private - --> $DIR/xcrate-private-by-default.rs:37:29 + --> $DIR/private-by-default.rs:37:29 | LL | static_priv_by_default::foo::b; | ^^^ - function `b` is not publicly re-exported @@ -87,7 +87,7 @@ LL | mod foo { | ^^^^^^^ error[E0603]: module `foo` is private - --> $DIR/xcrate-private-by-default.rs:39:29 + --> $DIR/private-by-default.rs:39:29 | LL | static_priv_by_default::foo::c; | ^^^ - unit struct `c` is not publicly re-exported @@ -101,7 +101,7 @@ LL | mod foo { | ^^^^^^^ error[E0603]: module `foo` is private - --> $DIR/xcrate-private-by-default.rs:41:35 + --> $DIR/private-by-default.rs:41:35 | LL | foo::<static_priv_by_default::foo::d>(); | ^^^ - enum `d` is not publicly re-exported @@ -115,7 +115,7 @@ LL | mod foo { | ^^^^^^^ error[E0603]: module `foo` is private - --> $DIR/xcrate-private-by-default.rs:43:35 + --> $DIR/private-by-default.rs:43:35 | LL | foo::<static_priv_by_default::foo::e>(); | ^^^ - type alias `e` is not publicly re-exported diff --git a/tests/ui/cross-crate/xcrate-static-addresses.rs b/tests/ui/cross-crate/static-addresses.rs index 66ac467e9ac..66ac467e9ac 100644 --- a/tests/ui/cross-crate/xcrate-static-addresses.rs +++ b/tests/ui/cross-crate/static-addresses.rs diff --git a/tests/ui/cross-crate/xcrate-trait-lifetime-param.rs b/tests/ui/cross-crate/trait-lifetime-param.rs index 28955e62d95..28955e62d95 100644 --- a/tests/ui/cross-crate/xcrate-trait-lifetime-param.rs +++ b/tests/ui/cross-crate/trait-lifetime-param.rs diff --git a/tests/ui/xcrate/xcrate-unit-struct-2.rs b/tests/ui/cross-crate/unit-struct-2.rs index c2e3a761129..c2e3a761129 100644 --- a/tests/ui/xcrate/xcrate-unit-struct-2.rs +++ b/tests/ui/cross-crate/unit-struct-2.rs diff --git a/tests/ui/xcrate/xcrate-unit-struct.rs b/tests/ui/cross-crate/unit-struct.rs index 1517f843eff..1517f843eff 100644 --- a/tests/ui/xcrate/xcrate-unit-struct.rs +++ b/tests/ui/cross-crate/unit-struct.rs diff --git a/tests/ui/xcrate/xcrate-unit-struct.stderr b/tests/ui/cross-crate/unit-struct.stderr index 7365170b69e..a7e3e4685a9 100644 --- a/tests/ui/xcrate/xcrate-unit-struct.stderr +++ b/tests/ui/cross-crate/unit-struct.stderr @@ -1,5 +1,5 @@ error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithFields` - --> $DIR/xcrate-unit-struct.rs:9:13 + --> $DIR/unit-struct.rs:9:13 | LL | let _ = xcrate_unit_struct::StructWithFields; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }` @@ -10,7 +10,7 @@ LL | pub struct StructWithFields { | --------------------------- `xcrate_unit_struct::StructWithFields` defined here error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithPrivFields` - --> $DIR/xcrate-unit-struct.rs:11:13 + --> $DIR/unit-struct.rs:11:13 | LL | let _ = xcrate_unit_struct::StructWithPrivFields; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/expr-block-fn.rs b/tests/ui/expr/block-fn.rs index 1d3689eb4f3..1d3689eb4f3 100644 --- a/tests/ui/expr-block-fn.rs +++ b/tests/ui/expr/block-fn.rs diff --git a/tests/ui/expr-block-generic.rs b/tests/ui/expr/block-generic.rs index b36bda917d6..b36bda917d6 100644 --- a/tests/ui/expr-block-generic.rs +++ b/tests/ui/expr/block-generic.rs diff --git a/tests/ui/expr-block.rs b/tests/ui/expr/block.rs index bf626c9ead3..bf626c9ead3 100644 --- a/tests/ui/expr-block.rs +++ b/tests/ui/expr/block.rs diff --git a/tests/ui/expr-copy.rs b/tests/ui/expr/copy.rs index cfe47ff6d93..cfe47ff6d93 100644 --- a/tests/ui/expr-copy.rs +++ b/tests/ui/expr/copy.rs diff --git a/tests/ui/expr-if-generic.rs b/tests/ui/expr/if-generic.rs index ed99ee63a51..ed99ee63a51 100644 --- a/tests/ui/expr-if-generic.rs +++ b/tests/ui/expr/if-generic.rs diff --git a/tests/ui/expr-if-panic-all.rs b/tests/ui/expr/if-panic-all.rs index 2ba2a36d165..2ba2a36d165 100644 --- a/tests/ui/expr-if-panic-all.rs +++ b/tests/ui/expr/if-panic-all.rs diff --git a/tests/ui/expr-scope.rs b/tests/ui/expr/scope.rs index 57321ce2aa0..57321ce2aa0 100644 --- a/tests/ui/expr-scope.rs +++ b/tests/ui/expr/scope.rs diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index bd3b69c2b4a..ca60bc62b51 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -45,7 +45,7 @@ mod inline { //~| NOTE not a function or closure #[inline = "2100"] fn f() { } - //~^ ERROR attribute must be of the form + //~^ ERROR valid forms for the attribute are //~| WARN this was previously accepted //~| NOTE #[deny(ill_formed_attribute_input)]` on by default //~| NOTE for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 89fa2abffc2..ac2bf78157d 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -7,7 +7,7 @@ LL | #![rustc_main] = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` +error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5 | LL | #[inline = "2100"] fn f() { } diff --git a/tests/ui/stmt_expr_attrs_no_feature.rs b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs index a160a9bb082..a160a9bb082 100644 --- a/tests/ui/stmt_expr_attrs_no_feature.rs +++ b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs diff --git a/tests/ui/stmt_expr_attrs_no_feature.stderr b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.stderr index c801268c652..c801268c652 100644 --- a/tests/ui/stmt_expr_attrs_no_feature.stderr +++ b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.stderr diff --git a/tests/ui/ffi_const.rs b/tests/ui/ffi-attrs/ffi_const.rs index aa20a4d4c65..aa20a4d4c65 100644 --- a/tests/ui/ffi_const.rs +++ b/tests/ui/ffi-attrs/ffi_const.rs diff --git a/tests/ui/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr index 394b98f8971..394b98f8971 100644 --- a/tests/ui/ffi_const.stderr +++ b/tests/ui/ffi-attrs/ffi_const.stderr diff --git a/tests/ui/ffi_const2.rs b/tests/ui/ffi-attrs/ffi_const2.rs index 82fe8a9c91d..82fe8a9c91d 100644 --- a/tests/ui/ffi_const2.rs +++ b/tests/ui/ffi-attrs/ffi_const2.rs diff --git a/tests/ui/ffi_const2.stderr b/tests/ui/ffi-attrs/ffi_const2.stderr index b8cbc296370..b8cbc296370 100644 --- a/tests/ui/ffi_const2.stderr +++ b/tests/ui/ffi-attrs/ffi_const2.stderr diff --git a/tests/ui/ffi_pure.rs b/tests/ui/ffi-attrs/ffi_pure.rs index 6d2f3a614ec..6d2f3a614ec 100644 --- a/tests/ui/ffi_pure.rs +++ b/tests/ui/ffi-attrs/ffi_pure.rs diff --git a/tests/ui/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr index 8b61a4b609f..8b61a4b609f 100644 --- a/tests/ui/ffi_pure.stderr +++ b/tests/ui/ffi-attrs/ffi_pure.stderr diff --git a/tests/ui/main-wrong-location.rs b/tests/ui/fn-main/wrong-location.rs index d7deeaed99d..d7deeaed99d 100644 --- a/tests/ui/main-wrong-location.rs +++ b/tests/ui/fn-main/wrong-location.rs diff --git a/tests/ui/main-wrong-location.stderr b/tests/ui/fn-main/wrong-location.stderr index 9486a940562..c47092bc47e 100644 --- a/tests/ui/main-wrong-location.stderr +++ b/tests/ui/fn-main/wrong-location.stderr @@ -1,11 +1,11 @@ -error[E0601]: `main` function not found in crate `main_wrong_location` - --> $DIR/main-wrong-location.rs:5:2 +error[E0601]: `main` function not found in crate `wrong_location` + --> $DIR/wrong-location.rs:5:2 | LL | } - | ^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`) + | ^ the main function must be defined at the crate level (in `$DIR/wrong-location.rs`) | note: here is a function named `main` - --> $DIR/main-wrong-location.rs:4:5 + --> $DIR/wrong-location.rs:4:5 | LL | fn main() { } | ^^^^^^^^^ diff --git a/tests/ui/main-wrong-type.rs b/tests/ui/fn-main/wrong-type.rs index 31deba72af4..31deba72af4 100644 --- a/tests/ui/main-wrong-type.rs +++ b/tests/ui/fn-main/wrong-type.rs diff --git a/tests/ui/main-wrong-type.stderr b/tests/ui/fn-main/wrong-type.stderr index d07fc09064f..2b0096431db 100644 --- a/tests/ui/main-wrong-type.stderr +++ b/tests/ui/fn-main/wrong-type.stderr @@ -1,5 +1,5 @@ error[E0580]: `main` function has wrong type - --> $DIR/main-wrong-type.rs:6:1 + --> $DIR/wrong-type.rs:6:1 | LL | fn main(foo: S) { | ^^^^^^^^^^^^^^^ incorrect number of function parameters diff --git a/tests/ui/foreign-fn-return-lifetime.rs b/tests/ui/foreign/foreign-fn-return-lifetime.rs index 35595bab36d..35595bab36d 100644 --- a/tests/ui/foreign-fn-return-lifetime.rs +++ b/tests/ui/foreign/foreign-fn-return-lifetime.rs diff --git a/tests/ui/foreign-fn-return-lifetime.stderr b/tests/ui/foreign/foreign-fn-return-lifetime.stderr index e24c0f23c35..e24c0f23c35 100644 --- a/tests/ui/foreign-fn-return-lifetime.stderr +++ b/tests/ui/foreign/foreign-fn-return-lifetime.stderr diff --git a/tests/ui/optimization-fuel-0.rs b/tests/ui/fuel/optimization-fuel-0.rs index cbcb1d329a3..cbcb1d329a3 100644 --- a/tests/ui/optimization-fuel-0.rs +++ b/tests/ui/fuel/optimization-fuel-0.rs diff --git a/tests/ui/optimization-fuel-0.stderr b/tests/ui/fuel/optimization-fuel-0.stderr index f0e2ebfc37a..f0e2ebfc37a 100644 --- a/tests/ui/optimization-fuel-0.stderr +++ b/tests/ui/fuel/optimization-fuel-0.stderr diff --git a/tests/ui/optimization-fuel-1.rs b/tests/ui/fuel/optimization-fuel-1.rs index 97edb0bd259..97edb0bd259 100644 --- a/tests/ui/optimization-fuel-1.rs +++ b/tests/ui/fuel/optimization-fuel-1.rs diff --git a/tests/ui/optimization-fuel-1.stderr b/tests/ui/fuel/optimization-fuel-1.stderr index 53eafb05830..53eafb05830 100644 --- a/tests/ui/optimization-fuel-1.stderr +++ b/tests/ui/fuel/optimization-fuel-1.stderr diff --git a/tests/ui/print-fuel/print-fuel.rs b/tests/ui/fuel/print-fuel.rs index fd7e568bea7..fd7e568bea7 100644 --- a/tests/ui/print-fuel/print-fuel.rs +++ b/tests/ui/fuel/print-fuel.rs diff --git a/tests/ui/print-fuel/print-fuel.stderr b/tests/ui/fuel/print-fuel.stderr index cc88cc077bb..cc88cc077bb 100644 --- a/tests/ui/print-fuel/print-fuel.stderr +++ b/tests/ui/fuel/print-fuel.stderr diff --git a/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs new file mode 100644 index 00000000000..b2ac332b4f0 --- /dev/null +++ b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs @@ -0,0 +1,28 @@ +#![allow(dead_code)] + +trait Trait1<T> + where T: for<'a> Trait1<T> + 'b { } //~ ERROR use of undeclared lifetime name `'b` + +trait Trait2<T> +where + T: B<'b> + for<'a> A<'a>, //~ ERROR use of undeclared lifetime name `'b` +{ +} + +trait Trait3<T> +where + T: B<'b> + for<'a> A<'a> + 'c {} + //~^ ERROR use of undeclared lifetime name `'b` + //~| ERROR use of undeclared lifetime name `'c` + +trait Trait4<T> +where + T: for<'a> A<'a> + 'x + for<'b> B<'b>, //~ ERROR use of undeclared lifetime name `'x` +{ +} + +trait A<'a> {} +trait B<'a> {} + + +fn main() {} diff --git a/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr new file mode 100644 index 00000000000..40f0769964f --- /dev/null +++ b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr @@ -0,0 +1,92 @@ +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:4:32 + | +LL | where T: for<'a> Trait1<T> + 'b { } + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL - where T: for<'a> Trait1<T> + 'b { } +LL + where for<'b, 'a> T: Trait1<T> + 'b { } + | +help: consider introducing lifetime `'b` here + | +LL | trait Trait1<'b, T> + | +++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:8:10 + | +LL | T: B<'b> + for<'a> A<'a>, + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | T: for<'b> B<'b> + for<'a> A<'a>, + | +++++++ +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL - T: B<'b> + for<'a> A<'a>, +LL + for<'b, 'a> T: B<'b> + A<'a>, + | +help: consider introducing lifetime `'b` here + | +LL | trait Trait2<'b, T> + | +++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:10 + | +LL | T: B<'b> + for<'a> A<'a> + 'c {} + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | T: for<'b> B<'b> + for<'a> A<'a> + 'c {} + | +++++++ +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL - T: B<'b> + for<'a> A<'a> + 'c {} +LL + for<'b, 'a> T: B<'b> + A<'a> + 'c {} + | +help: consider introducing lifetime `'b` here + | +LL | trait Trait3<'b, T> + | +++ + +error[E0261]: use of undeclared lifetime name `'c` + --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:32 + | +LL | T: B<'b> + for<'a> A<'a> + 'c {} + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'c` lifetime + | +LL - T: B<'b> + for<'a> A<'a> + 'c {} +LL + for<'c, 'a> T: B<'b> + A<'a> + 'c {} + | +help: consider introducing lifetime `'c` here + | +LL | trait Trait3<'c, T> + | +++ + +error[E0261]: use of undeclared lifetime name `'x` + --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:20:24 + | +LL | T: for<'a> A<'a> + 'x + for<'b> B<'b>, + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'x` lifetime + | +LL - T: for<'a> A<'a> + 'x + for<'b> B<'b>, +LL + for<'x, 'a, 'b> T: A<'a> + 'x + B<'b>, + | +help: consider introducing lifetime `'x` here + | +LL | trait Trait4<'x, T> + | +++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/infer-fn-tail-expr.rs b/tests/ui/inference/infer-fn-tail-expr.rs index 31b71e49bd6..31b71e49bd6 100644 --- a/tests/ui/infer-fn-tail-expr.rs +++ b/tests/ui/inference/infer-fn-tail-expr.rs diff --git a/tests/ui/lambda-infer-unresolved.rs b/tests/ui/inference/lambda-infer-unresolved.rs index f30832044dc..f30832044dc 100644 --- a/tests/ui/lambda-infer-unresolved.rs +++ b/tests/ui/inference/lambda-infer-unresolved.rs diff --git a/tests/ui/order-dependent-cast-inference.rs b/tests/ui/inference/order-dependent-cast-inference.rs index e666209b912..e666209b912 100644 --- a/tests/ui/order-dependent-cast-inference.rs +++ b/tests/ui/inference/order-dependent-cast-inference.rs diff --git a/tests/ui/order-dependent-cast-inference.stderr b/tests/ui/inference/order-dependent-cast-inference.stderr index ab33b703a05..ab33b703a05 100644 --- a/tests/ui/order-dependent-cast-inference.stderr +++ b/tests/ui/inference/order-dependent-cast-inference.stderr diff --git a/tests/ui/intrinsics-always-extern.rs b/tests/ui/intrinsics/always-extern.rs index 0afd8353455..0afd8353455 100644 --- a/tests/ui/intrinsics-always-extern.rs +++ b/tests/ui/intrinsics/always-extern.rs diff --git a/tests/ui/intrinsics-always-extern.stderr b/tests/ui/intrinsics/always-extern.stderr index 1f7bb5a3b0d..44b889c6faa 100644 --- a/tests/ui/intrinsics-always-extern.stderr +++ b/tests/ui/intrinsics/always-extern.stderr @@ -1,11 +1,11 @@ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/intrinsics-always-extern.rs:4:32 + --> $DIR/always-extern.rs:4:32 | LL | extern "rust-intrinsic" fn foo(&self); | ^^^ error[E0093]: unrecognized intrinsic function: `hello` - --> $DIR/intrinsics-always-extern.rs:12:28 + --> $DIR/always-extern.rs:12:28 | LL | extern "rust-intrinsic" fn hello() { | ^^^^^ unrecognized intrinsic @@ -13,7 +13,7 @@ LL | extern "rust-intrinsic" fn hello() { = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type` error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/intrinsics-always-extern.rs:8:43 + --> $DIR/always-extern.rs:8:43 | LL | extern "rust-intrinsic" fn foo(&self) { | ___________________________________________^ @@ -21,7 +21,7 @@ LL | | } | |_____^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/intrinsics-always-extern.rs:12:36 + --> $DIR/always-extern.rs:12:36 | LL | extern "rust-intrinsic" fn hello() { | ____________________________________^ diff --git a/tests/ui/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs index 6c52651f060..6c52651f060 100644 --- a/tests/ui/reify-intrinsic.rs +++ b/tests/ui/intrinsics/reify-intrinsic.rs diff --git a/tests/ui/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr index 0119a1a6650..0119a1a6650 100644 --- a/tests/ui/reify-intrinsic.stderr +++ b/tests/ui/intrinsics/reify-intrinsic.stderr diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr index e3854a5459e..c4ee18fe8da 100644 --- a/tests/ui/lint/anonymous-reexport.stderr +++ b/tests/ui/lint/anonymous-reexport.stderr @@ -34,7 +34,7 @@ error: unused import: `Bar as _` LL | pub use self::my_mod::{Bar as _, Foo as _}; | ^^^^^^^^ -error: unused imports: `Bar as _`, `TyBar as _` +error: unused imports: `Bar as _` and `TyBar as _` --> $DIR/anonymous-reexport.rs:17:24 | LL | pub use self::my_mod::{Bar as _, TyBar as _}; diff --git a/tests/ui/lint-group-denied-lint-allowed.rs b/tests/ui/lint/group-denied-lint-allowed.rs index 86b63bb31e3..86b63bb31e3 100644 --- a/tests/ui/lint-group-denied-lint-allowed.rs +++ b/tests/ui/lint/group-denied-lint-allowed.rs diff --git a/tests/ui/lint-group-forbid-always-trumps-cli.rs b/tests/ui/lint/group-forbid-always-trumps-cli.rs index 4b63452bf5d..4b63452bf5d 100644 --- a/tests/ui/lint-group-forbid-always-trumps-cli.rs +++ b/tests/ui/lint/group-forbid-always-trumps-cli.rs diff --git a/tests/ui/lint-group-forbid-always-trumps-cli.stderr b/tests/ui/lint/group-forbid-always-trumps-cli.stderr index 04a0f56c163..21674ebae9c 100644 --- a/tests/ui/lint-group-forbid-always-trumps-cli.stderr +++ b/tests/ui/lint/group-forbid-always-trumps-cli.stderr @@ -1,5 +1,5 @@ error: unused variable: `x` - --> $DIR/lint-group-forbid-always-trumps-cli.rs:4:9 + --> $DIR/group-forbid-always-trumps-cli.rs:4:9 | LL | let x = 1; | ^ help: if this is intentional, prefix it with an underscore: `_x` diff --git a/tests/ui/lint-unknown-lints-at-crate-level.rs b/tests/ui/lint/unknown-lints-at-crate-level.rs index c8cf65ce93a..c8cf65ce93a 100644 --- a/tests/ui/lint-unknown-lints-at-crate-level.rs +++ b/tests/ui/lint/unknown-lints-at-crate-level.rs diff --git a/tests/ui/lint/unused/import_remove_line.stderr b/tests/ui/lint/unused/import_remove_line.stderr index 0e8c5de3558..b2a16669a93 100644 --- a/tests/ui/lint/unused/import_remove_line.stderr +++ b/tests/ui/lint/unused/import_remove_line.stderr @@ -1,4 +1,4 @@ -warning: unused imports: `Duration`, `Instant` +warning: unused imports: `Duration` and `Instant` --> $DIR/import_remove_line.rs:7:17 | LL | use std::time::{Duration, Instant}; diff --git a/tests/ui/lint/unused/lint-unused-imports.rs b/tests/ui/lint/unused/lint-unused-imports.rs index 88f2baa5da9..710fb7a5ed1 100644 --- a/tests/ui/lint/unused/lint-unused-imports.rs +++ b/tests/ui/lint/unused/lint-unused-imports.rs @@ -10,7 +10,7 @@ use std::fmt::{}; // Should get errors for both 'Some' and 'None' use std::option::Option::{Some, None}; -//~^ ERROR unused imports: `None`, `Some` +//~^ ERROR unused imports: `None` and `Some` use test::A; //~ ERROR unused import: `test::A` // Be sure that if we just bring some methods into scope that they're also diff --git a/tests/ui/lint/unused/lint-unused-imports.stderr b/tests/ui/lint/unused/lint-unused-imports.stderr index 07684a84a64..a848fb31eba 100644 --- a/tests/ui/lint/unused/lint-unused-imports.stderr +++ b/tests/ui/lint/unused/lint-unused-imports.stderr @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(unused_imports)] | ^^^^^^^^^^^^^^ -error: unused imports: `None`, `Some` +error: unused imports: `None` and `Some` --> $DIR/lint-unused-imports.rs:12:27 | LL | use std::option::Option::{Some, None}; diff --git a/tests/ui/compile_error_macro.rs b/tests/ui/macros/compile_error_macro.rs index 3f7b57cd078..3f7b57cd078 100644 --- a/tests/ui/compile_error_macro.rs +++ b/tests/ui/macros/compile_error_macro.rs diff --git a/tests/ui/compile_error_macro.stderr b/tests/ui/macros/compile_error_macro.stderr index 92d5564e8a7..92d5564e8a7 100644 --- a/tests/ui/compile_error_macro.stderr +++ b/tests/ui/macros/compile_error_macro.stderr diff --git a/tests/ui/module-macro_use-arguments.rs b/tests/ui/macros/module-macro_use-arguments.rs index 121b492e254..121b492e254 100644 --- a/tests/ui/module-macro_use-arguments.rs +++ b/tests/ui/macros/module-macro_use-arguments.rs diff --git a/tests/ui/module-macro_use-arguments.stderr b/tests/ui/macros/module-macro_use-arguments.stderr index 3ac645ad3a9..3ac645ad3a9 100644 --- a/tests/ui/module-macro_use-arguments.stderr +++ b/tests/ui/macros/module-macro_use-arguments.stderr diff --git a/tests/ui/no-patterns-in-args-macro.rs b/tests/ui/macros/no-patterns-in-args-macro.rs index b5109f9c286..b5109f9c286 100644 --- a/tests/ui/no-patterns-in-args-macro.rs +++ b/tests/ui/macros/no-patterns-in-args-macro.rs diff --git a/tests/ui/no-patterns-in-args-macro.stderr b/tests/ui/macros/no-patterns-in-args-macro.stderr index 0016c7953f3..0016c7953f3 100644 --- a/tests/ui/no-patterns-in-args-macro.stderr +++ b/tests/ui/macros/no-patterns-in-args-macro.stderr diff --git a/tests/ui/malformed/malformed-regressions.rs b/tests/ui/malformed/malformed-regressions.rs index ac1444bbaef..f0a7aac59c1 100644 --- a/tests/ui/malformed/malformed-regressions.rs +++ b/tests/ui/malformed/malformed-regressions.rs @@ -1,8 +1,8 @@ -#[doc] //~ ERROR attribute must be of the form +#[doc] //~ ERROR valid forms for the attribute are //~^ WARN this was previously accepted -#[ignore()] //~ ERROR attribute must be of the form +#[ignore()] //~ ERROR valid forms for the attribute are //~^ WARN this was previously accepted -#[inline = ""] //~ ERROR attribute must be of the form +#[inline = ""] //~ ERROR valid forms for the attribute are //~^ WARN this was previously accepted #[link] //~ ERROR attribute must be of the form //~^ WARN this was previously accepted diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 9bfbe7ebafd..e1dbdb9ab3c 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -1,4 +1,4 @@ -error: attribute must be of the form `#[doc(hidden|inline|...)]` or `#[doc = "string"]` +error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]` --> $DIR/malformed-regressions.rs:1:1 | LL | #[doc] @@ -8,7 +8,7 @@ LL | #[doc] = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> = note: `#[deny(ill_formed_attribute_input)]` on by default -error: attribute must be of the form `#[ignore]` or `#[ignore = "reason"]` +error: valid forms for the attribute are `#[ignore]` and `#[ignore = "reason"]` --> $DIR/malformed-regressions.rs:3:1 | LL | #[ignore()] @@ -17,7 +17,7 @@ LL | #[ignore()] = 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 #57571 <https://github.com/rust-lang/rust/issues/57571> -error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` +error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` --> $DIR/malformed-regressions.rs:5:1 | LL | #[inline = ""] diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs new file mode 100644 index 00000000000..3c0059ba3e3 --- /dev/null +++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs @@ -0,0 +1,6 @@ +// Regression test for issue #124935 +// Tests that we do not erroneously emit an error about +// missing main function when the mod starts with a `;` + +; //~ ERROR expected item, found `;` +fn main() { } diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr new file mode 100644 index 00000000000..9776677589f --- /dev/null +++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr @@ -0,0 +1,8 @@ +error: expected item, found `;` + --> $DIR/fn-no-semicolon-issue-124935-semi-after-item.rs:5:1 + | +LL | ; + | ^ help: remove this semicolon + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/issue-49040.rs b/tests/ui/parser/issues/issue-49040.rs index b7a541dd664..68e7cc9f80e 100644 --- a/tests/ui/parser/issues/issue-49040.rs +++ b/tests/ui/parser/issues/issue-49040.rs @@ -1,3 +1,3 @@ #![allow(unused_variables)]; //~ ERROR expected item, found `;` -//~^ ERROR `main` function fn foo() {} +//~^ ERROR `main` function diff --git a/tests/ui/parser/issues/issue-49040.stderr b/tests/ui/parser/issues/issue-49040.stderr index 8af7838c791..11ef5e1aadf 100644 --- a/tests/ui/parser/issues/issue-49040.stderr +++ b/tests/ui/parser/issues/issue-49040.stderr @@ -5,10 +5,10 @@ LL | #![allow(unused_variables)]; | ^ help: remove this semicolon error[E0601]: `main` function not found in crate `issue_49040` - --> $DIR/issue-49040.rs:1:29 + --> $DIR/issue-49040.rs:2:12 | -LL | #![allow(unused_variables)]; - | ^ consider adding a `main` function to `$DIR/issue-49040.rs` +LL | fn foo() {} + | ^ consider adding a `main` function to `$DIR/issue-49040.rs` error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs new file mode 100644 index 00000000000..3fbac5fae23 --- /dev/null +++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs @@ -0,0 +1,5 @@ +// Regression test for issue #124935 +// Tests that we still emit an error after an item. + +fn main() { } +; //~ ERROR expected item, found `;` diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr new file mode 100644 index 00000000000..2d7f540443d --- /dev/null +++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr @@ -0,0 +1,10 @@ +error: expected item, found `;` + --> $DIR/missing-main-issue-124935-semi-after-item.rs:5:1 + | +LL | ; + | ^ help: remove this semicolon + | + = help: function declarations are not followed by a semicolon + +error: aborting due to 1 previous error + diff --git a/tests/ui/super-fast-paren-parsing.rs b/tests/ui/parser/super-fast-paren-parsing.rs index ce7283eee03..5b7cd6fe47d 100644 --- a/tests/ui/super-fast-paren-parsing.rs +++ b/tests/ui/parser/super-fast-paren-parsing.rs @@ -3,10 +3,7 @@ #![allow(unused_parens)] #![allow(non_upper_case_globals)] #![allow(dead_code)] -//@ exec-env:RUST_MIN_STACK=16000000 -//@ rustc-env:RUST_MIN_STACK=16000000 -// -// Big stack is needed for pretty printing, a little sad... +#![cfg_attr(rustfmt, rustfmt::skip)] static a: isize = ((((((((((((((((((((((((((((((((((((((((((((((((((( diff --git a/tests/ui/by-move-pattern-binding.rs b/tests/ui/pattern/by-move-pattern-binding.rs index f68d181291d..f68d181291d 100644 --- a/tests/ui/by-move-pattern-binding.rs +++ b/tests/ui/pattern/by-move-pattern-binding.rs diff --git a/tests/ui/by-move-pattern-binding.stderr b/tests/ui/pattern/by-move-pattern-binding.stderr index 203e37dc387..203e37dc387 100644 --- a/tests/ui/by-move-pattern-binding.stderr +++ b/tests/ui/pattern/by-move-pattern-binding.stderr diff --git a/tests/ui/fn-in-pat.rs b/tests/ui/pattern/fn-in-pat.rs index 2d7c86b8666..2d7c86b8666 100644 --- a/tests/ui/fn-in-pat.rs +++ b/tests/ui/pattern/fn-in-pat.rs diff --git a/tests/ui/fn-in-pat.stderr b/tests/ui/pattern/fn-in-pat.stderr index 41ea4df72a2..41ea4df72a2 100644 --- a/tests/ui/fn-in-pat.stderr +++ b/tests/ui/pattern/fn-in-pat.stderr diff --git a/tests/ui/inc-range-pat.rs b/tests/ui/pattern/inc-range-pat.rs index 189dac4feed..189dac4feed 100644 --- a/tests/ui/inc-range-pat.rs +++ b/tests/ui/pattern/inc-range-pat.rs diff --git a/tests/ui/no-patterns-in-args-2.rs b/tests/ui/pattern/no-patterns-in-args-2.rs index 85b7fc5cdba..85b7fc5cdba 100644 --- a/tests/ui/no-patterns-in-args-2.rs +++ b/tests/ui/pattern/no-patterns-in-args-2.rs diff --git a/tests/ui/no-patterns-in-args-2.stderr b/tests/ui/pattern/no-patterns-in-args-2.stderr index 6adcbb9dccd..6adcbb9dccd 100644 --- a/tests/ui/no-patterns-in-args-2.stderr +++ b/tests/ui/pattern/no-patterns-in-args-2.stderr diff --git a/tests/ui/no-patterns-in-args.rs b/tests/ui/pattern/no-patterns-in-args.rs index 54836b0a3f5..54836b0a3f5 100644 --- a/tests/ui/no-patterns-in-args.rs +++ b/tests/ui/pattern/no-patterns-in-args.rs diff --git a/tests/ui/no-patterns-in-args.stderr b/tests/ui/pattern/no-patterns-in-args.stderr index 1c2ce866467..1c2ce866467 100644 --- a/tests/ui/no-patterns-in-args.stderr +++ b/tests/ui/pattern/no-patterns-in-args.stderr diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs index 653dcab5771..796ba4d2332 100644 --- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs +++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs @@ -6,7 +6,7 @@ mod rank { pub use self::Lieutenant::{JuniorGrade, Full}; //~^ ERROR `JuniorGrade` is private, and cannot be re-exported //~| ERROR `Full` is private, and cannot be re-exported - //~| ERROR unused imports: `Full`, `JuniorGrade` + //~| ERROR unused imports: `Full` and `JuniorGrade` pub use self::PettyOfficer::*; //~^ ERROR glob import doesn't reexport anything //~| ERROR unused import: `self::PettyOfficer::*` diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr index 93a39edbb82..f1701d547a6 100644 --- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr +++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr @@ -46,7 +46,7 @@ error: unused import: `self::Professor::*` LL | pub use self::Professor::*; | ^^^^^^^^^^^^^^^^^^ -error: unused imports: `Full`, `JuniorGrade` +error: unused imports: `Full` and `JuniorGrade` --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32 | LL | pub use self::Lieutenant::{JuniorGrade, Full}; diff --git a/tests/ui/env-args-reverse-iterator.rs b/tests/ui/process/env-args-reverse-iterator.rs index 830e9535466..830e9535466 100644 --- a/tests/ui/env-args-reverse-iterator.rs +++ b/tests/ui/process/env-args-reverse-iterator.rs diff --git a/tests/ui/env-funky-keys.rs b/tests/ui/process/env-funky-keys.rs index 314ccaea015..314ccaea015 100644 --- a/tests/ui/env-funky-keys.rs +++ b/tests/ui/process/env-funky-keys.rs diff --git a/tests/ui/env-null-vars.rs b/tests/ui/process/env-null-vars.rs index 24d783553d1..24d783553d1 100644 --- a/tests/ui/env-null-vars.rs +++ b/tests/ui/process/env-null-vars.rs diff --git a/tests/ui/env-vars.rs b/tests/ui/process/env-vars.rs index 73068b5dfb8..73068b5dfb8 100644 --- a/tests/ui/env-vars.rs +++ b/tests/ui/process/env-vars.rs diff --git a/tests/ui/exec-env.rs b/tests/ui/process/exec-env.rs index 9054b378f56..9054b378f56 100644 --- a/tests/ui/exec-env.rs +++ b/tests/ui/process/exec-env.rs diff --git a/tests/ui/inherit-env.rs b/tests/ui/process/inherit-env.rs index 0eb61fcdd53..0eb61fcdd53 100644 --- a/tests/ui/inherit-env.rs +++ b/tests/ui/process/inherit-env.rs diff --git a/tests/ui/impossible_range.fixed b/tests/ui/range/impossible_range.fixed index 423dde94f4f..423dde94f4f 100644 --- a/tests/ui/impossible_range.fixed +++ b/tests/ui/range/impossible_range.fixed diff --git a/tests/ui/impossible_range.rs b/tests/ui/range/impossible_range.rs index 002ea792fbf..002ea792fbf 100644 --- a/tests/ui/impossible_range.rs +++ b/tests/ui/range/impossible_range.rs diff --git a/tests/ui/impossible_range.stderr b/tests/ui/range/impossible_range.stderr index 53c56065c2a..53c56065c2a 100644 --- a/tests/ui/impossible_range.stderr +++ b/tests/ui/range/impossible_range.stderr diff --git a/tests/ui/range_inclusive.rs b/tests/ui/range/range_inclusive.rs index 6e77f0d7767..6e77f0d7767 100644 --- a/tests/ui/range_inclusive.rs +++ b/tests/ui/range/range_inclusive.rs diff --git a/tests/ui/conflicting-repr-hints.rs b/tests/ui/repr/conflicting-repr-hints.rs index ed82b6a742c..ed82b6a742c 100644 --- a/tests/ui/conflicting-repr-hints.rs +++ b/tests/ui/repr/conflicting-repr-hints.rs diff --git a/tests/ui/conflicting-repr-hints.stderr b/tests/ui/repr/conflicting-repr-hints.stderr index 4dcd8f4fc28..4dcd8f4fc28 100644 --- a/tests/ui/conflicting-repr-hints.stderr +++ b/tests/ui/repr/conflicting-repr-hints.stderr diff --git a/tests/ui/ret-bang.rs b/tests/ui/return/ret-bang.rs index f0d529ad6a6..f0d529ad6a6 100644 --- a/tests/ui/ret-bang.rs +++ b/tests/ui/return/ret-bang.rs diff --git a/tests/ui/ret-non-nil.rs b/tests/ui/return/ret-non-nil.rs index 1d039ffe18c..1d039ffe18c 100644 --- a/tests/ui/ret-non-nil.rs +++ b/tests/ui/return/ret-non-nil.rs diff --git a/tests/ui/ret-non-nil.stderr b/tests/ui/return/ret-non-nil.stderr index 802900e61a3..802900e61a3 100644 --- a/tests/ui/ret-non-nil.stderr +++ b/tests/ui/return/ret-non-nil.stderr diff --git a/tests/ui/return-disjoint-regions.rs b/tests/ui/return/return-disjoint-regions.rs index d0feb3b65e1..d0feb3b65e1 100644 --- a/tests/ui/return-disjoint-regions.rs +++ b/tests/ui/return/return-disjoint-regions.rs diff --git a/tests/ui/return-disjoint-regions.stderr b/tests/ui/return/return-disjoint-regions.stderr index 7b5b032579a..7b5b032579a 100644 --- a/tests/ui/return-disjoint-regions.stderr +++ b/tests/ui/return/return-disjoint-regions.stderr diff --git a/tests/ui/return-nil.rs b/tests/ui/return/return-nil.rs index 403eae260dc..403eae260dc 100644 --- a/tests/ui/return-nil.rs +++ b/tests/ui/return/return-nil.rs diff --git a/tests/ui/span/multispan-import-lint.stderr b/tests/ui/span/multispan-import-lint.stderr index 4a955d1b31f..a4ea1af237b 100644 --- a/tests/ui/span/multispan-import-lint.stderr +++ b/tests/ui/span/multispan-import-lint.stderr @@ -1,4 +1,4 @@ -warning: unused imports: `Eq`, `Ord`, `PartialEq`, `PartialOrd` +warning: unused imports: `Eq`, `Ord`, `PartialEq`, and `PartialOrd` --> $DIR/multispan-import-lint.rs:5:16 | LL | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; diff --git a/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs b/tests/ui/statics/auxiliary/check_static_recursion_foreign_helper.rs index bcab5f238c3..bcab5f238c3 100644 --- a/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs +++ b/tests/ui/statics/auxiliary/check_static_recursion_foreign_helper.rs diff --git a/tests/ui/check-static-immutable-mut-slices.rs b/tests/ui/statics/check-immutable-mut-slices.rs index 8f9680778aa..8f9680778aa 100644 --- a/tests/ui/check-static-immutable-mut-slices.rs +++ b/tests/ui/statics/check-immutable-mut-slices.rs diff --git a/tests/ui/check-static-immutable-mut-slices.stderr b/tests/ui/statics/check-immutable-mut-slices.stderr index 402f9032b64..5cb35a7c21e 100644 --- a/tests/ui/check-static-immutable-mut-slices.stderr +++ b/tests/ui/statics/check-immutable-mut-slices.stderr @@ -1,5 +1,5 @@ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/check-static-immutable-mut-slices.rs:3:37 + --> $DIR/check-immutable-mut-slices.rs:3:37 | LL | static TEST: &'static mut [isize] = &mut []; | ^^^^^^^ diff --git a/tests/ui/check-static-recursion-foreign.rs b/tests/ui/statics/check-recursion-foreign.rs index 5a0ff7b5962..5a0ff7b5962 100644 --- a/tests/ui/check-static-recursion-foreign.rs +++ b/tests/ui/statics/check-recursion-foreign.rs diff --git a/tests/ui/check-static-values-constraints.rs b/tests/ui/statics/check-values-constraints.rs index 005a7798895..005a7798895 100644 --- a/tests/ui/check-static-values-constraints.rs +++ b/tests/ui/statics/check-values-constraints.rs diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr index fe5f2a34272..45a699f575f 100644 --- a/tests/ui/check-static-values-constraints.stderr +++ b/tests/ui/statics/check-values-constraints.stderr @@ -1,5 +1,5 @@ error[E0493]: destructor of `SafeStruct` cannot be evaluated at compile-time - --> $DIR/check-static-values-constraints.rs:64:7 + --> $DIR/check-values-constraints.rs:64:7 | LL | ..SafeStruct { | _______^ @@ -12,7 +12,7 @@ LL | }; | - value is dropped here error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:81:33 + --> $DIR/check-values-constraints.rs:81:33 | LL | static STATIC11: Vec<MyOwned> = vec![MyOwned]; | ^^^^^^^^^^^^^ allocation not allowed in statics @@ -20,7 +20,7 @@ LL | static STATIC11: Vec<MyOwned> = vec![MyOwned]; = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics - --> $DIR/check-static-values-constraints.rs:81:33 + --> $DIR/check-values-constraints.rs:81:33 | LL | static STATIC11: Vec<MyOwned> = vec![MyOwned]; | ^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | static STATIC11: Vec<MyOwned> = vec![MyOwned]; = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `<str as ToString>::to_string` in statics - --> $DIR/check-static-values-constraints.rs:92:38 + --> $DIR/check-values-constraints.rs:92:38 | LL | field2: SafeEnum::Variant4("str".to_string()), | ^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL + #![feature(const_trait_impl)] | error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:96:5 + --> $DIR/check-values-constraints.rs:96:5 | LL | vec![MyOwned], | ^^^^^^^^^^^^^ allocation not allowed in statics @@ -51,7 +51,7 @@ LL | vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics - --> $DIR/check-static-values-constraints.rs:96:5 + --> $DIR/check-values-constraints.rs:96:5 | LL | vec![MyOwned], | ^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:98:5 + --> $DIR/check-values-constraints.rs:98:5 | LL | vec![MyOwned], | ^^^^^^^^^^^^^ allocation not allowed in statics @@ -69,7 +69,7 @@ LL | vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics - --> $DIR/check-static-values-constraints.rs:98:5 + --> $DIR/check-values-constraints.rs:98:5 | LL | vec![MyOwned], | ^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:103:6 + --> $DIR/check-values-constraints.rs:103:6 | LL | &vec![MyOwned], | ^^^^^^^^^^^^^ allocation not allowed in statics @@ -87,7 +87,7 @@ LL | &vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics - --> $DIR/check-static-values-constraints.rs:103:6 + --> $DIR/check-values-constraints.rs:103:6 | LL | &vec![MyOwned], | ^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | &vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:105:6 + --> $DIR/check-values-constraints.rs:105:6 | LL | &vec![MyOwned], | ^^^^^^^^^^^^^ allocation not allowed in statics @@ -105,7 +105,7 @@ LL | &vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics - --> $DIR/check-static-values-constraints.rs:105:6 + --> $DIR/check-values-constraints.rs:105:6 | LL | &vec![MyOwned], | ^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL | &vec![MyOwned], = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:111:31 + --> $DIR/check-values-constraints.rs:111:31 | LL | static STATIC19: Vec<isize> = vec![3]; | ^^^^^^^ allocation not allowed in statics @@ -123,7 +123,7 @@ LL | static STATIC19: Vec<isize> = vec![3]; = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics - --> $DIR/check-static-values-constraints.rs:111:31 + --> $DIR/check-values-constraints.rs:111:31 | LL | static STATIC19: Vec<isize> = vec![3]; | ^^^^^^^ @@ -133,7 +133,7 @@ LL | static STATIC19: Vec<isize> = vec![3]; = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:117:32 + --> $DIR/check-values-constraints.rs:117:32 | LL | static x: Vec<isize> = vec![3]; | ^^^^^^^ allocation not allowed in statics @@ -141,7 +141,7 @@ LL | static x: Vec<isize> = vec![3]; = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics - --> $DIR/check-static-values-constraints.rs:117:32 + --> $DIR/check-values-constraints.rs:117:32 | LL | static x: Vec<isize> = vec![3]; | ^^^^^^^ @@ -151,7 +151,7 @@ LL | static x: Vec<isize> = vec![3]; = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0507]: cannot move out of static item `x` - --> $DIR/check-static-values-constraints.rs:119:9 + --> $DIR/check-values-constraints.rs:119:9 | LL | x | ^ move occurs because `x` has type `Vec<isize>`, which does not implement the `Copy` trait diff --git a/tests/ui/dont-suggest-private-trait-method.rs b/tests/ui/suggestions/dont-suggest-private-trait-method.rs index 6e2b1abd137..6e2b1abd137 100644 --- a/tests/ui/dont-suggest-private-trait-method.rs +++ b/tests/ui/suggestions/dont-suggest-private-trait-method.rs diff --git a/tests/ui/dont-suggest-private-trait-method.stderr b/tests/ui/suggestions/dont-suggest-private-trait-method.stderr index f251ad59a58..f251ad59a58 100644 --- a/tests/ui/dont-suggest-private-trait-method.stderr +++ b/tests/ui/suggestions/dont-suggest-private-trait-method.stderr diff --git a/tests/ui/suggest-null-ptr.fixed b/tests/ui/suggestions/suggest-null-ptr.fixed index 55c90859c83..55c90859c83 100644 --- a/tests/ui/suggest-null-ptr.fixed +++ b/tests/ui/suggestions/suggest-null-ptr.fixed diff --git a/tests/ui/suggest-null-ptr.rs b/tests/ui/suggestions/suggest-null-ptr.rs index f4f1269d512..f4f1269d512 100644 --- a/tests/ui/suggest-null-ptr.rs +++ b/tests/ui/suggestions/suggest-null-ptr.rs diff --git a/tests/ui/suggest-null-ptr.stderr b/tests/ui/suggestions/suggest-null-ptr.stderr index 66a79d0749e..66a79d0749e 100644 --- a/tests/ui/suggest-null-ptr.stderr +++ b/tests/ui/suggestions/suggest-null-ptr.stderr diff --git a/tests/ui/trait-impl-bound-suggestions.fixed b/tests/ui/suggestions/trait-impl-bound-suggestions.fixed index 9d3168f5acd..9d3168f5acd 100644 --- a/tests/ui/trait-impl-bound-suggestions.fixed +++ b/tests/ui/suggestions/trait-impl-bound-suggestions.fixed diff --git a/tests/ui/trait-impl-bound-suggestions.rs b/tests/ui/suggestions/trait-impl-bound-suggestions.rs index 342fb4416ad..342fb4416ad 100644 --- a/tests/ui/trait-impl-bound-suggestions.rs +++ b/tests/ui/suggestions/trait-impl-bound-suggestions.rs diff --git a/tests/ui/trait-impl-bound-suggestions.stderr b/tests/ui/suggestions/trait-impl-bound-suggestions.stderr index 6a75cbdf639..6a75cbdf639 100644 --- a/tests/ui/trait-impl-bound-suggestions.stderr +++ b/tests/ui/suggestions/trait-impl-bound-suggestions.stderr diff --git a/tests/ui/suggestions/unused-imports.stderr b/tests/ui/suggestions/unused-imports.stderr index bf112608da7..31edb4e5ec2 100644 --- a/tests/ui/suggestions/unused-imports.stderr +++ b/tests/ui/suggestions/unused-imports.stderr @@ -1,4 +1,4 @@ -warning: unused imports: `A`, `C` +warning: unused imports: `A` and `C` --> $DIR/unused-imports.rs:22:14 | LL | use nested::{A, B, C}; @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![warn(unused_imports)] | ^^^^^^^^^^^^^^ -warning: unused imports: `D`, `E`, `G` +warning: unused imports: `D`, `E`, and `G` --> $DIR/unused-imports.rs:26:5 | LL | D, diff --git a/tests/ui/tool_lints-fail.rs b/tests/ui/tool-attributes/tool_lints-fail.rs index 5cbd63be597..5cbd63be597 100644 --- a/tests/ui/tool_lints-fail.rs +++ b/tests/ui/tool-attributes/tool_lints-fail.rs diff --git a/tests/ui/tool_lints-fail.stderr b/tests/ui/tool-attributes/tool_lints-fail.stderr index 7d80e0728f7..7d80e0728f7 100644 --- a/tests/ui/tool_lints-fail.stderr +++ b/tests/ui/tool-attributes/tool_lints-fail.stderr diff --git a/tests/ui/tool_lints-rpass.rs b/tests/ui/tool-attributes/tool_lints-rpass.rs index 458eca19ed6..458eca19ed6 100644 --- a/tests/ui/tool_lints-rpass.rs +++ b/tests/ui/tool-attributes/tool_lints-rpass.rs diff --git a/tests/ui/tool_lints.rs b/tests/ui/tool-attributes/tool_lints.rs index ef27532f6de..ef27532f6de 100644 --- a/tests/ui/tool_lints.rs +++ b/tests/ui/tool-attributes/tool_lints.rs diff --git a/tests/ui/tool_lints.stderr b/tests/ui/tool-attributes/tool_lints.stderr index f1d825caba1..f1d825caba1 100644 --- a/tests/ui/tool_lints.stderr +++ b/tests/ui/tool-attributes/tool_lints.stderr diff --git a/tests/ui/tool_lints_2018_preview.rs b/tests/ui/tool-attributes/tool_lints_2018_preview.rs index 458eca19ed6..458eca19ed6 100644 --- a/tests/ui/tool_lints_2018_preview.rs +++ b/tests/ui/tool-attributes/tool_lints_2018_preview.rs diff --git a/tests/ui/unknown-lint-tool-name.rs b/tests/ui/tool-attributes/unknown-lint-tool-name.rs index cd5d2f028af..cd5d2f028af 100644 --- a/tests/ui/unknown-lint-tool-name.rs +++ b/tests/ui/tool-attributes/unknown-lint-tool-name.rs diff --git a/tests/ui/unknown-lint-tool-name.stderr b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr index 72731ab1e3d..72731ab1e3d 100644 --- a/tests/ui/unknown-lint-tool-name.stderr +++ b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr diff --git a/tests/ui/unknown-tool-name.rs b/tests/ui/tool-attributes/unknown-tool-name.rs index 73fca61c65d..73fca61c65d 100644 --- a/tests/ui/unknown-tool-name.rs +++ b/tests/ui/tool-attributes/unknown-tool-name.rs diff --git a/tests/ui/unknown-tool-name.stderr b/tests/ui/tool-attributes/unknown-tool-name.stderr index 361d359a10e..361d359a10e 100644 --- a/tests/ui/unknown-tool-name.stderr +++ b/tests/ui/tool-attributes/unknown-tool-name.stderr diff --git a/tests/ui/unop-move-semantics.rs b/tests/ui/unop/unop-move-semantics.rs index 8168da8242f..8168da8242f 100644 --- a/tests/ui/unop-move-semantics.rs +++ b/tests/ui/unop/unop-move-semantics.rs diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop/unop-move-semantics.stderr index bc9b3ea9903..bc9b3ea9903 100644 --- a/tests/ui/unop-move-semantics.stderr +++ b/tests/ui/unop/unop-move-semantics.stderr diff --git a/tests/ui/unop-neg-bool.rs b/tests/ui/unop/unop-neg-bool.rs index 6f1f1aba459..6f1f1aba459 100644 --- a/tests/ui/unop-neg-bool.rs +++ b/tests/ui/unop/unop-neg-bool.rs diff --git a/tests/ui/unop-neg-bool.stderr b/tests/ui/unop/unop-neg-bool.stderr index 9bc5e7dcf22..9bc5e7dcf22 100644 --- a/tests/ui/unop-neg-bool.stderr +++ b/tests/ui/unop/unop-neg-bool.stderr diff --git a/tests/ui/use/use-nested-groups-unused-imports.rs b/tests/ui/use/use-nested-groups-unused-imports.rs index ca6b8ba94d1..0c8ae558a59 100644 --- a/tests/ui/use/use-nested-groups-unused-imports.rs +++ b/tests/ui/use/use-nested-groups-unused-imports.rs @@ -13,7 +13,7 @@ mod foo { } use foo::{Foo, bar::{baz::{}, foobar::*}, *}; - //~^ ERROR unused imports: `*`, `Foo`, `baz::{}`, `foobar::*` + //~^ ERROR unused imports: `*`, `Foo`, `baz::{}`, and `foobar::*` use foo::bar::baz::{*, *}; //~^ ERROR unused import: `*` use foo::{}; diff --git a/tests/ui/use/use-nested-groups-unused-imports.stderr b/tests/ui/use/use-nested-groups-unused-imports.stderr index 6610f8ecd4a..dd39a852772 100644 --- a/tests/ui/use/use-nested-groups-unused-imports.stderr +++ b/tests/ui/use/use-nested-groups-unused-imports.stderr @@ -1,4 +1,4 @@ -error: unused imports: `*`, `Foo`, `baz::{}`, `foobar::*` +error: unused imports: `*`, `Foo`, `baz::{}`, and `foobar::*` --> $DIR/use-nested-groups-unused-imports.rs:15:11 | LL | use foo::{Foo, bar::{baz::{}, foobar::*}, *}; |
