diff --git a/.mailmap b/.mailmap index a586e7047769c..4c254b396b538 100644 --- a/.mailmap +++ b/.mailmap @@ -431,6 +431,7 @@ Lzu Tao Maik Klein Maja Kądziołka Maja Kądziołka +Makai Malo Jaffré Manish Goregaokar Mara Bos diff --git a/Cargo.lock b/Cargo.lock index d818d87e08045..d189eddc3b6bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -621,7 +621,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clippy" -version = "0.1.93" +version = "0.1.94" dependencies = [ "anstream", "askama", @@ -648,7 +648,7 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.93" +version = "0.1.94" dependencies = [ "clippy_utils", "itertools", @@ -671,7 +671,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.93" +version = "0.1.94" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -703,7 +703,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.93" +version = "0.1.94" dependencies = [ "arrayvec", "itertools", @@ -1107,7 +1107,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.93" +version = "0.1.94" [[package]] name = "derive-where" diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index f2642838b3c8c..61f816f0baf8f 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,9 +6,6 @@ attr_parsing_bundle_needs_static = attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters -attr_parsing_cfg_predicate_identifier = - `cfg` predicate key must be an identifier - attr_parsing_deprecated_item_suggestion = suggestions on deprecated items are unstable .help = add `#![feature(deprecated_suggestion)]` to the crate root @@ -41,9 +38,6 @@ attr_parsing_empty_link_name = link name must not be empty .label = empty link name -attr_parsing_expected_one_cfg_pattern = - expected 1 cfg-pattern - attr_parsing_expected_single_version_literal = expected single version literal @@ -241,12 +235,6 @@ attr_parsing_unstable_cfg_target_compact = attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` -attr_parsing_unsupported_literal_cfg_boolean = - literal in `cfg` predicate value must be a boolean -attr_parsing_unsupported_literal_cfg_string = - literal in `cfg` predicate value must be a string -attr_parsing_unsupported_literal_generic = - unsupported literal attr_parsing_unsupported_literal_suggestion = consider removing the prefix diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 088fa73d74278..79f7171cc0c86 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -17,9 +17,9 @@ impl CombineAttributeParser for AllowInternalUnstableParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) .into_iter() @@ -39,9 +39,9 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> impl IntoIterator { if !cx.features().staged_api() { cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); @@ -67,17 +67,17 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) } } fn parse_unstable( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, symbol: Symbol, ) -> impl IntoIterator { let mut res = Vec::new(); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 6ffe25098308a..5b4786a64ef2d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -4,7 +4,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token}; use rustc_errors::{Applicability, PResult}; -use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template}; +use rustc_feature::{ + AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template, +}; use rustc_hir::attrs::CfgEntry; use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrPath, RustcVersion}; @@ -23,7 +25,7 @@ use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, }; -use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg}; +use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics}; pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], @@ -35,9 +37,9 @@ const CFG_ATTR_TEMPLATE: AttributeTemplate = template!( "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute" ); -pub fn parse_cfg<'c, S: Stage>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, +pub fn parse_cfg( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> Option { let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); @@ -52,7 +54,7 @@ pub fn parse_cfg<'c, S: Stage>( pub fn parse_cfg_entry( cx: &mut AcceptContext<'_, '_, S>, - item: &MetaItemOrLitParser<'_>, + item: &MetaItemOrLitParser, ) -> Result { Ok(match item { MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { @@ -98,7 +100,7 @@ pub fn parse_cfg_entry( fn parse_cfg_entry_version( cx: &mut AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, meta_span: Span, ) -> Result { try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); @@ -130,7 +132,7 @@ fn parse_cfg_entry_version( fn parse_cfg_entry_target( cx: &mut AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, meta_span: Span, ) -> Result { if let Some(features) = cx.features_option() @@ -410,3 +412,19 @@ fn parse_cfg_attr_internal<'a>( Ok((cfg_predicate, expanded_attrs)) } + +fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { + let gate = find_gated_cfg(|sym| sym == name); + if let (Some(feats), Some(gated_cfg)) = (features, gate) { + gate_cfg(gated_cfg, span, sess, feats); + } +} + +#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable +fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { + let (cfg, feature, has_feature) = gated_cfg; + if !has_feature(features) && !cfg_span.allows_unstable(*feature) { + let explain = format!("`cfg({cfg})` is experimental and subject to change"); + feature_err(sess, *feature, cfg_span, explain).emit(); + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs deleted file mode 100644 index acb234480d5dd..0000000000000 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ /dev/null @@ -1,210 +0,0 @@ -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_feature::{Features, GatedCfg, find_gated_cfg}; -use rustc_hir::RustcVersion; -use rustc_session::Session; -use rustc_session::lint::{BuiltinLintDiag, Lint}; -use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; - -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; -use crate::{fluent_generated, parse_version}; - -/// Emitter of a builtin lint from `cfg_matches`. -/// -/// Used to support emitting a lint (currently on check-cfg), either: -/// - as an early buffered lint (in `rustc`) -/// - or has a "normal" lint from HIR (in `rustdoc`) -pub trait CfgMatchesLintEmitter { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag); -} - -impl CfgMatchesLintEmitter for NodeId { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) { - sess.psess.buffer_lint(lint, sp, *self, diag); - } -} - -#[derive(Clone, Debug)] -pub struct Condition { - pub name: Symbol, - pub name_span: Span, - pub value: Option, - pub value_span: Option, - pub span: Span, -} - -pub fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| sym == name); - if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(gated_cfg, span, sess, feats); - } -} - -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { - let (cfg, feature, has_feature) = gated_cfg; - if !has_feature(features) && !cfg_span.allows_unstable(*feature) { - let explain = format!("`cfg({cfg})` is experimental and subject to change"); - feature_err(sess, *feature, cfg_span, explain).emit(); - } -} - -/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to -/// evaluate individual items. -pub fn eval_condition( - cfg: &MetaItemInner, - sess: &Session, - features: Option<&Features>, - eval: &mut impl FnMut(Condition) -> bool, -) -> bool { - let dcx = sess.dcx(); - - let cfg = match cfg { - MetaItemInner::MetaItem(meta_item) => meta_item, - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - return *b; - } - _ => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: cfg.span(), - reason: UnsupportedLiteralReason::CfgBoolean, - is_bytestr: false, - start_point_span: sess.source_map().start_point(cfg.span()), - }); - return false; - } - }; - - match &cfg.kind { - MetaItemKind::List(mis) if cfg.has_name(sym::version) => { - try_gate_cfg(sym::version, cfg.span, sess, features); - let (min_version, span) = match &mis[..] { - [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { - (sym, span) - } - [ - MetaItemInner::Lit(MetaItemLit { span, .. }) - | MetaItemInner::MetaItem(MetaItem { span, .. }), - ] => { - dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); - return false; - } - [..] => { - dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { - span: cfg.span, - }); - return false; - } - }; - let Some(min_version) = parse_version(*min_version) else { - dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span }); - return false; - }; - - // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details - if sess.psess.assume_incomplete_release { - RustcVersion::current_overridable() > min_version - } else { - RustcVersion::current_overridable() >= min_version - } - } - MetaItemKind::List(mis) => { - for mi in mis.iter() { - if mi.meta_item_or_bool().is_none() { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: mi.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: sess.source_map().start_point(mi.span()), - }); - return false; - } - } - - // The unwraps below may look dangerous, but we've already asserted - // that they won't fail with the loop above. - match cfg.name() { - Some(sym::any) => mis - .iter() - // We don't use any() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), - Some(sym::all) => mis - .iter() - // We don't use all() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), - Some(sym::not) => { - let [mi] = mis.as_slice() else { - dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); - return false; - }; - - !eval_condition(mi, sess, features, eval) - } - Some(sym::target) => { - if let Some(features) = features - && !features.cfg_target_compact() - { - feature_err( - sess, - sym::cfg_target_compact, - cfg.span, - fluent_generated::attr_parsing_unstable_cfg_target_compact, - ) - .emit(); - } - - mis.iter().fold(true, |res, mi| { - let Some(mut mi) = mi.meta_item().cloned() else { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { - span: mi.span(), - }); - return false; - }; - - if let [seg, ..] = &mut mi.path.segments[..] { - seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); - } - - res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval) - }) - } - _ => { - dcx.emit_err(session_diagnostics::InvalidPredicate { - span: cfg.span, - predicate: pprust::path_to_string(&cfg.path), - }); - false - } - } - } - MetaItemKind::Word | MetaItemKind::NameValue(..) - if cfg.path.segments.len() != 1 - || cfg.path.segments[0].ident.is_path_segment_keyword() => - { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); - true - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::CfgString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: sess.source_map().start_point(lit.span), - }); - true - } - MetaItemKind::Word | MetaItemKind::NameValue(..) => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - eval(Condition { - name: ident.name, - name_span: ident.span, - value: cfg.value_str(), - value_span: cfg.name_value_literal_span(), - span: cfg.span, - }) - } - } -} diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index b4ecbe6e4de6f..7d3a7418f06c3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -23,7 +23,7 @@ impl SingleAttributeParser for OptimizeParser { ]); const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; @@ -84,7 +84,7 @@ impl SingleAttributeParser for CoverageParser { ]); const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(args) = args.list() else { cx.expected_specific_argument_and_list(cx.attr_span, &[sym::on, sym::off]); return None; @@ -135,7 +135,7 @@ impl SingleAttributeParser for ExportNameParser { ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -164,7 +164,7 @@ impl SingleAttributeParser for ObjcClassParser { AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -196,7 +196,7 @@ impl SingleAttributeParser for ObjcSelectorParser { AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -472,10 +472,10 @@ impl AttributeParser for UsedParser { } } -fn parse_tf_attribute<'c, S: Stage>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, -) -> impl IntoIterator + 'c { +fn parse_tf_attribute( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, +) -> impl IntoIterator { let mut features = Vec::new(); let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); @@ -529,10 +529,10 @@ impl CombineAttributeParser for TargetFeatureParser { }; const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_tf_attribute(cx, args) } @@ -567,10 +567,10 @@ impl CombineAttributeParser for ForceTargetFeatureParser { Allow(Target::Method(MethodKind::TraitImpl)), ]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_tf_attribute(cx, args) } } @@ -599,7 +599,7 @@ impl SingleAttributeParser for SanitizeParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 480a32658bc57..01c503357fc79 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -11,7 +11,7 @@ impl SingleAttributeParser for CrateNameParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(n) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -35,7 +35,7 @@ impl SingleAttributeParser for RecursionLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -58,7 +58,7 @@ impl SingleAttributeParser for MoveSizeLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -81,7 +81,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -104,7 +104,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -154,7 +154,7 @@ impl SingleAttributeParser for WindowsSubsystemParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value( args.span().unwrap_or(cx.inner_span), diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 56ff10be42640..c88b795aab03d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -16,10 +16,10 @@ impl CombineAttributeParser for DebuggerViualizerParser { type Item = DebugVisualizer; const CONVERT: ConvertFn = |v, _| AttributeKind::DebuggerVisualizer(v); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let Some(l) = args.list() else { cx.expected_list(args.span().unwrap_or(cx.attr_span)); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index f96477e28cd0b..ad3e2ced60c7d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -12,7 +12,7 @@ fn get( cx: &AcceptContext<'_, '_, S>, name: Symbol, param_span: Span, - arg: &ArgParser<'_>, + arg: &ArgParser, item: &Option, ) -> Option { if item.is_some() { @@ -68,7 +68,7 @@ impl SingleAttributeParser for DeprecationParser { NameValueStr: "reason" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let features = cx.features(); let mut since = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 547f00d140415..b6fea37c92aa2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -10,7 +10,7 @@ use thin_vec::ThinVec; use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; -use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; +use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, DocKeywordNotKeyword, @@ -43,10 +43,10 @@ fn check_attribute( false } -fn parse_keyword_and_attribute<'c, S, F>( - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, +fn parse_keyword_and_attribute( + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, attr_value: &mut Option<(Symbol, Span)>, callback: F, ) where @@ -82,10 +82,10 @@ pub(crate) struct DocParser { } impl DocParser { - fn parse_single_test_doc_attr_item<'c, S: Stage>( + fn parse_single_test_doc_attr_item( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - mip: &'c MetaItemParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + mip: &MetaItemParser, ) { let path = mip.path(); let args = mip.args(); @@ -132,9 +132,9 @@ impl DocParser { } } - fn add_alias<'c, S: Stage>( + fn add_alias( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, + cx: &mut AcceptContext<'_, '_, S>, alias: Symbol, span: Span, ) { @@ -167,11 +167,11 @@ impl DocParser { self.attribute.aliases.insert(alias, span); } - fn parse_alias<'c, S: Stage>( + fn parse_alias( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { @@ -197,11 +197,11 @@ impl DocParser { } } - fn parse_inline<'c, S: Stage>( + fn parse_inline( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, inline: DocInline, ) { if let Err(span) = args.no_args() { @@ -212,11 +212,7 @@ impl DocParser { self.attribute.inline.push((inline, path.span())); } - fn parse_cfg<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, - ) { + fn parse_cfg(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { // This function replaces cases like `cfg(all())` with `true`. fn simplify_cfg(cfg_entry: &mut CfgEntry) { match cfg_entry { @@ -236,11 +232,11 @@ impl DocParser { } } - fn parse_auto_cfg<'c, S: Stage>( + fn parse_auto_cfg( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { @@ -343,10 +339,10 @@ impl DocParser { } } - fn parse_single_doc_attr_item<'c, S: Stage>( + fn parse_single_doc_attr_item( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - mip: &MetaItemParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + mip: &MetaItemParser, ) { let path = mip.path(); let args = mip.args(); @@ -506,10 +502,10 @@ impl DocParser { } } - fn accept_single_doc_attr<'c, S: Stage>( + fn accept_single_doc_attr( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 7293cee842c28..0a7d95f31799d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for DummyParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really - fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser<'_>) -> Option { + fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option { Some(AttributeKind::Dummy) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index fba1a663c0575..f6aab9ea0ee2a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -34,7 +34,7 @@ impl SingleAttributeParser for InlineParser { "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { match args { ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { @@ -77,7 +77,7 @@ impl SingleAttributeParser for RustcForceInlineParser { const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let reason = match args { ArgParser::NoArgs => None, ArgParser::List(list) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 46fa8ee713438..fe8f3578fe145 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -33,7 +33,7 @@ impl SingleAttributeParser for LinkNameParser { "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -62,10 +62,10 @@ impl CombineAttributeParser for LinkParser { ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let items = match args { ArgParser::List(list) => list, // This is an edgecase added because making this a hard error would break too many crates @@ -242,7 +242,7 @@ impl CombineAttributeParser for LinkParser { impl LinkParser { fn parse_link_name( - item: &MetaItemParser<'_>, + item: &MetaItemParser, name: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -267,7 +267,7 @@ impl LinkParser { } fn parse_link_kind( - item: &MetaItemParser<'_>, + item: &MetaItemParser, kind: &mut Option, cx: &mut AcceptContext<'_, '_, S>, sess: &Session, @@ -347,7 +347,7 @@ impl LinkParser { } fn parse_link_modifiers( - item: &MetaItemParser<'_>, + item: &MetaItemParser, modifiers: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -368,7 +368,7 @@ impl LinkParser { } fn parse_link_cfg( - item: &MetaItemParser<'_>, + item: &MetaItemParser, cfg: &mut Option, cx: &mut AcceptContext<'_, '_, S>, sess: &Session, @@ -400,7 +400,7 @@ impl LinkParser { } fn parse_link_wasm_import_module( - item: &MetaItemParser<'_>, + item: &MetaItemParser, wasm_import_module: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -421,7 +421,7 @@ impl LinkParser { } fn parse_link_import_name_type( - item: &MetaItemParser<'_>, + item: &MetaItemParser, import_name_type: &mut Option<(PeImportNameType, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -478,7 +478,7 @@ impl SingleAttributeParser for LinkSectionParser { "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -551,7 +551,7 @@ impl SingleAttributeParser for LinkOrdinalParser { "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ordinal = parse_single_integer(cx, args)?; // According to the table at @@ -607,7 +607,7 @@ impl SingleAttributeParser for LinkageParser { "weak_odr", ]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(name_value) = args.name_value() else { cx.expected_name_value(cx.attr_span, Some(sym::linkage)); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index d2fa1d440f407..e4209c3edd85c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -148,7 +148,7 @@ impl SingleAttributeParser for MacroExportParser { Error(Target::Crate), ]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let local_inner_macros = match args { ArgParser::NoArgs => false, ArgParser::List(list) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 64bcb02b0b745..64f29a4729c3d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -32,7 +32,6 @@ mod prelude; pub(crate) mod allow_unstable; pub(crate) mod body; pub(crate) mod cfg; -pub(crate) mod cfg_old; pub(crate) mod cfg_select; pub(crate) mod codegen_attrs; pub(crate) mod confusables; @@ -62,7 +61,7 @@ pub(crate) mod traits; pub(crate) mod transparency; pub(crate) mod util; -type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); +type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser); type AcceptMapping = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. @@ -133,7 +132,7 @@ pub(crate) trait SingleAttributeParser: 'static { const TEMPLATE: AttributeTemplate; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option; + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option; } /// Use in combination with [`SingleAttributeParser`]. @@ -282,7 +281,7 @@ impl, S: Stage> SingleAttributeParser for Without const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { cx.expected_no_args(span); } @@ -315,10 +314,10 @@ pub(crate) trait CombineAttributeParser: 'static { const TEMPLATE: AttributeTemplate; /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) -> impl IntoIterator + 'c; + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator; } /// Use in combination with [`CombineAttributeParser`]. diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index 51b43e96adf99..a27e1ecb707e3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -29,7 +29,7 @@ impl SingleAttributeParser for MustUseParser { "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::MustUse { span: cx.attr_span, reason: match args { diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index e4cb806bb4277..b60f8e315e5ef 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -13,7 +13,7 @@ impl SingleAttributeParser for PathParser { "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index b9929d6f1f8ee..e1762005d4c4a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -30,7 +30,7 @@ impl SingleAttributeParser for ProcMacroDeriveParser { "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?; Some(AttributeKind::ProcMacroDerive { trait_name: trait_name.expect("Trait name is mandatory, so it is present"), @@ -49,7 +49,7 @@ impl SingleAttributeParser for RustcBuiltinMacroParser { const TEMPLATE: AttributeTemplate = template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?; Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span }) } @@ -57,7 +57,7 @@ impl SingleAttributeParser for RustcBuiltinMacroParser { fn parse_derive_like( cx: &mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, trait_name_mandatory: bool, ) -> Option<(Option, ThinVec)> { let Some(list) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index 80fe82bf54295..cd7c84f45fe51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -25,7 +25,7 @@ impl SingleAttributeParser for CustomMirParser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; @@ -70,7 +70,7 @@ impl SingleAttributeParser for CustomMirParser { fn extract_value( cx: &mut AcceptContext<'_, '_, S>, key: Symbol, - arg: &ArgParser<'_>, + arg: &ArgParser, span: Span, out_val: &mut Option<(Symbol, Span)>, failed: &mut bool, diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 0330e2515c7df..4520e4f5dbac1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -26,10 +26,10 @@ impl CombineAttributeParser for ReprParser { "https://doc.rust-lang.org/reference/type-layout.html#representations" ); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let mut reprs = Vec::new(); let Some(list) = args.list() else { @@ -98,10 +98,7 @@ fn int_type_of_word(s: Symbol) -> Option { } } -fn parse_repr( - cx: &AcceptContext<'_, '_, S>, - param: &MetaItemParser<'_>, -) -> Option { +fn parse_repr(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -> Option { use ReprAttr::*; // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the @@ -192,7 +189,7 @@ enum AlignKind { fn parse_repr_align( cx: &AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, param_span: Span, align_kind: AlignKind, ) -> Option { @@ -278,11 +275,7 @@ impl AlignParser { const PATH: &'static [Symbol] = &[sym::rustc_align]; const TEMPLATE: AttributeTemplate = template!(List: &[""]); - fn parse<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) { + fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { match args { ArgParser::NoArgs | ArgParser::NameValue(_) => { cx.expected_list(cx.attr_span); @@ -339,11 +332,7 @@ impl AlignStaticParser { const PATH: &'static [Symbol] = &[sym::rustc_align_static]; const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; - fn parse<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) { + fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { self.0.parse(cx, args) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 455c61097d78d..d51fa2510b936 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -19,7 +19,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeStartPars const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["start"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { parse_single_integer(cx, args) .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span)) } @@ -34,7 +34,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeEndParser const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["end"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { parse_single_integer(cx, args) .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span)) } @@ -49,7 +49,7 @@ impl SingleAttributeParser for RustcObjectLifetimeDefaultParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { cx.expected_no_args(span); return None; @@ -68,7 +68,7 @@ impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b94e23477ffeb..571cb884c1fcd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,7 +8,7 @@ use rustc_hir::{ use super::prelude::*; use super::util::parse_version; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; +use crate::session_diagnostics::{self}; macro_rules! reject_outside_std { ($cx: ident) => { @@ -267,7 +267,7 @@ impl AttributeParser for ConstStabilityParser { /// `name = value` fn insert_value_into_option_or_error( cx: &AcceptContext<'_, '_, S>, - param: &MetaItemParser<'_>, + param: &MetaItemParser, item: &mut Option, name: Ident, ) -> Option<()> { @@ -289,7 +289,7 @@ fn insert_value_into_option_or_error( /// its stability information. pub(crate) fn parse_stability( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut since = None; @@ -302,12 +302,7 @@ pub(crate) fn parse_stability( for param in list.mixed() { let param_span = param.span(); let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param_span, - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param_span), - }); + cx.unexpected_literal(param.span()); return None; }; @@ -365,7 +360,7 @@ pub(crate) fn parse_stability( /// attribute, and return the feature name and its stability information. pub(crate) fn parse_unstability( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut reason = None; @@ -382,12 +377,7 @@ pub(crate) fn parse_unstability( for param in list.mixed() { let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param.span()), - }); + cx.unexpected_literal(param.span()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index e0b006030758b..7f25641b948e2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for IgnoreParser { "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::Ignore { span: cx.attr_span, reason: match args { @@ -49,7 +49,7 @@ impl SingleAttributeParser for ShouldPanicParser { "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::ShouldPanic { span: cx.attr_span, reason: match args { diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 753892d1e9970..a9b76021a989d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -18,7 +18,7 @@ impl SingleAttributeParser for SkipDuringMethodDispatchParser { const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let mut array = false; let mut boxed_slice = false; let Some(args) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ea1f5549c4ec8..52aa42b1085a3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -17,7 +17,7 @@ impl SingleAttributeParser for TransparencyParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["transparent", "semitransparent", "opaque"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 105f7164bf3b3..4e3478abbf4fd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -40,7 +40,7 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { /// `args` is the parser for the attribute arguments. pub(crate) fn parse_single_integer( cx: &mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f41ea37087888..074f3b4194aee 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -75,7 +75,7 @@ use crate::attributes::traits::{ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; -use crate::parser::{ArgParser, PathParser}; +use crate::parser::{ArgParser, RefPathParser}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, ParsedDescription, UnknownMetaItem, }; @@ -95,7 +95,7 @@ pub(super) struct GroupTypeInnerAccept { } type AcceptFn = - Box Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>; + Box Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>; type FinalizeFn = Box) -> Option>; @@ -713,7 +713,7 @@ pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// /// Usually, you should use normal attribute parsing logic instead, /// especially when making a *denylist* of other attributes. - pub(crate) all_attrs: &'p [PathParser<'p>], + pub(crate) all_attrs: &'p [RefPathParser<'p>], } impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 5eefce75ace21..91596ff0de600 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,4 +1,4 @@ -use std::borrow::Cow; +use std::convert::identity; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; @@ -13,7 +13,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; -use crate::parser::{ArgParser, MetaItemParser, PathParser}; +use crate::parser::{ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -136,7 +136,7 @@ impl<'sess> AttributeParser<'sess, Early> { target_node_id: NodeId, features: Option<&'sess Features>, emit_errors: ShouldEmit, - parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option, template: &AttributeTemplate, ) -> Option { let ast::AttrKind::Normal(normal_attr) = &attr.kind else { @@ -144,22 +144,23 @@ impl<'sess> AttributeParser<'sess, Early> { }; let parts = normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); - let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?; - let path = meta_parser.path(); - let args = meta_parser.args(); + + let path = AttrPath::from_ast(&normal_attr.item.path, identity); + let args = + ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?; Self::parse_single_args( sess, attr.span, normal_attr.item.span(), attr.style, - path.get_attribute_path(), + path, Some(normal_attr.item.unsafety), ParsedDescription::Attribute, target_span, target_node_id, features, emit_errors, - args, + &args, parse_fn, template, ) @@ -267,7 +268,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { let mut attributes = Vec::new(); - let mut attr_paths = Vec::new(); + let mut attr_paths: Vec> = Vec::new(); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -301,7 +302,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { })) } ast::AttrKind::Normal(n) => { - attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); + attr_paths.push(PathParser(&n.item.path)); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); self.check_attribute_safety( @@ -316,15 +317,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { n.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { - let Some(parser) = MetaItemParser::from_attr( - n, + let Some(args) = ArgParser::from_attr_args( + &n.item.args, &parts, &self.sess.psess, self.stage.should_emit(), ) else { continue; }; - let args = parser.args(); // Special-case handling for `#[doc = "..."]`: if we go through with // `DocParser`, the order of doc comments will be messed up because `///` @@ -342,7 +342,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { // blob // a if is_doc_attribute - && let ArgParser::NameValue(nv) = args + && let ArgParser::NameValue(nv) = &args // If not a string key/value, it should emit an error, but to make // things simpler, it's handled in `DocParser` because it's simpler to // emit an error with `AcceptContext`. @@ -373,7 +373,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_path: attr_path.clone(), }; - (accept.accept_fn)(&mut cx, args); + (accept.accept_fn)(&mut cx, &args); if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { Self::check_target(&accept.allowed_targets, target, &mut cx); } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index cb02bb9d501fc..411b4dd75e661 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -107,7 +107,6 @@ pub mod validate_attr; pub use attributes::cfg::{ CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry, }; -pub use attributes::cfg_old::*; pub use attributes::cfg_select::*; pub use attributes::util::{is_builtin_attr, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 819e5630561d0..09ecfaedb5ed2 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -3,12 +3,12 @@ //! //! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs` -use std::borrow::Cow; +use std::borrow::Borrow; use std::fmt::{Debug, Display}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path, StmtKind, UnOp}; +use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, StmtKind, UnOp}; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; @@ -26,9 +26,12 @@ use crate::session_diagnostics::{ }; #[derive(Clone, Debug)] -pub struct PathParser<'a>(pub Cow<'a, Path>); +pub struct PathParser>(pub P); -impl<'a> PathParser<'a> { +pub type OwnedPathParser = PathParser; +pub type RefPathParser<'p> = PathParser<&'p Path>; + +impl> PathParser

{ pub fn get_attribute_path(&self) -> hir::AttrPath { AttrPath { segments: self.segments().copied().collect::>().into_boxed_slice(), @@ -36,16 +39,16 @@ impl<'a> PathParser<'a> { } } - pub fn segments(&'a self) -> impl Iterator { - self.0.segments.iter().map(|seg| &seg.ident) + pub fn segments(&self) -> impl Iterator { + self.0.borrow().segments.iter().map(|seg| &seg.ident) } pub fn span(&self) -> Span { - self.0.span + self.0.borrow().span } pub fn len(&self) -> usize { - self.0.segments.len() + self.0.borrow().segments.len() } pub fn segments_is(&self, segments: &[Symbol]) -> bool { @@ -76,21 +79,21 @@ impl<'a> PathParser<'a> { } } -impl Display for PathParser<'_> { +impl> Display for PathParser

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", pprust::path_to_string(&self.0)) + write!(f, "{}", pprust::path_to_string(self.0.borrow())) } } #[derive(Clone, Debug)] #[must_use] -pub enum ArgParser<'a> { +pub enum ArgParser { NoArgs, - List(MetaItemListParser<'a>), + List(MetaItemListParser), NameValue(NameValueParser), } -impl<'a> ArgParser<'a> { +impl ArgParser { pub fn span(&self) -> Option { match self { Self::NoArgs => None, @@ -100,7 +103,7 @@ impl<'a> ArgParser<'a> { } pub fn from_attr_args<'sess>( - value: &'a AttrArgs, + value: &AttrArgs, parts: &[Symbol], psess: &'sess ParseSess, should_emit: ShouldEmit, @@ -144,7 +147,7 @@ impl<'a> ArgParser<'a> { /// /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list - pub fn list(&self) -> Option<&MetaItemListParser<'a>> { + pub fn list(&self) -> Option<&MetaItemListParser> { match self { Self::List(l) => Some(l), Self::NameValue(_) | Self::NoArgs => None, @@ -184,17 +187,17 @@ impl<'a> ArgParser<'a> { /// /// Choose which one you want using the provided methods. #[derive(Debug, Clone)] -pub enum MetaItemOrLitParser<'a> { - MetaItemParser(MetaItemParser<'a>), +pub enum MetaItemOrLitParser { + MetaItemParser(MetaItemParser), Lit(MetaItemLit), Err(Span, ErrorGuaranteed), } -impl<'sess> MetaItemOrLitParser<'sess> { - pub fn parse_single( +impl MetaItemOrLitParser { + pub fn parse_single<'sess>( parser: &mut Parser<'sess>, should_emit: ShouldEmit, - ) -> PResult<'sess, MetaItemOrLitParser<'static>> { + ) -> PResult<'sess, MetaItemOrLitParser> { let mut this = MetaItemListParserContext { parser, should_emit }; this.parse_meta_item_inner() } @@ -216,7 +219,7 @@ impl<'sess> MetaItemOrLitParser<'sess> { } } - pub fn meta_item(&self) -> Option<&MetaItemParser<'sess>> { + pub fn meta_item(&self) -> Option<&MetaItemParser> { match self { MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), _ => None, @@ -238,12 +241,12 @@ impl<'sess> MetaItemOrLitParser<'sess> { /// /// The syntax of MetaItems can be found at #[derive(Clone)] -pub struct MetaItemParser<'a> { - path: PathParser<'a>, - args: ArgParser<'a>, +pub struct MetaItemParser { + path: OwnedPathParser, + args: ArgParser, } -impl<'a> Debug for MetaItemParser<'a> { +impl Debug for MetaItemParser { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MetaItemParser") .field("path", &self.path) @@ -252,28 +255,12 @@ impl<'a> Debug for MetaItemParser<'a> { } } -impl<'a> MetaItemParser<'a> { - /// Create a new parser from a [`NormalAttr`], which is stored inside of any - /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr<'sess>( - attr: &'a NormalAttr, - parts: &[Symbol], - psess: &'sess ParseSess, - should_emit: ShouldEmit, - ) -> Option { - Some(Self { - path: PathParser(Cow::Borrowed(&attr.item.path)), - args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?, - }) - } -} - -impl<'a> MetaItemParser<'a> { +impl MetaItemParser { pub fn span(&self) -> Span { if let Some(other) = self.args.span() { - self.path.span().with_hi(other.hi()) + self.path.borrow().span().with_hi(other.hi()) } else { - self.path.span() + self.path.borrow().span() } } @@ -282,12 +269,12 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> &PathParser<'a> { + pub fn path(&self) -> &OwnedPathParser { &self.path } /// Gets just the args parser, without caring about the path. - pub fn args(&self) -> &ArgParser<'a> { + pub fn args(&self) -> &ArgParser { &self.args } @@ -297,7 +284,7 @@ impl<'a> MetaItemParser<'a> { /// - `#[inline]`: `inline` is a word /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { + pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> { self.path().word_is(sym).then(|| self.args()) } } @@ -421,7 +408,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { Ok(lit) } - fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> { + fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> { if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() { return if has_meta_form { let attr_item = self @@ -457,10 +444,10 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { ArgParser::NoArgs }; - Ok(MetaItemParser { path: PathParser(Cow::Owned(path)), args }) + Ok(MetaItemParser { path: PathParser(path), args }) } - fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> { + fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { if let Some(token_lit) = self.parser.eat_token_lit() { // If a literal token is parsed, we commit to parsing a MetaItemLit for better errors Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) @@ -547,7 +534,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { psess: &'sess ParseSess, span: Span, should_emit: ShouldEmit, - ) -> PResult<'sess, MetaItemListParser<'static>> { + ) -> PResult<'sess, MetaItemListParser> { let mut parser = Parser::new(psess, tokens, None); let mut this = MetaItemListParserContext { parser: &mut parser, should_emit }; @@ -570,14 +557,14 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } #[derive(Debug, Clone)] -pub struct MetaItemListParser<'a> { - sub_parsers: ThinVec>, +pub struct MetaItemListParser { + sub_parsers: ThinVec, pub span: Span, } -impl<'a> MetaItemListParser<'a> { +impl MetaItemListParser { pub(crate) fn new<'sess>( - tokens: &'a TokenStream, + tokens: &TokenStream, span: Span, psess: &'sess ParseSess, should_emit: ShouldEmit, @@ -586,7 +573,7 @@ impl<'a> MetaItemListParser<'a> { } /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed(&self) -> impl Iterator> { + pub fn mixed(&self) -> impl Iterator { self.sub_parsers.iter() } @@ -601,7 +588,7 @@ impl<'a> MetaItemListParser<'a> { /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. - pub fn single(&self) -> Option<&MetaItemOrLitParser<'a>> { + pub fn single(&self) -> Option<&MetaItemOrLitParser> { let mut iter = self.mixed(); iter.next().filter(|_| iter.next().is_none()) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7bb55d2a6de5b..3adbe115b23b5 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -12,19 +12,6 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; -pub(crate) enum UnsupportedLiteralReason { - Generic, - CfgString, - CfgBoolean, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)] -pub(crate) struct ExpectedOneCfgPattern { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_predicate, code = E0537)] pub(crate) struct InvalidPredicate { @@ -230,46 +217,6 @@ pub(crate) struct InvalidReprHintNoValue { pub name: Symbol, } -/// Error code: E0565 -// FIXME(jdonszelmann): slowly phased out -pub(crate) struct UnsupportedLiteral { - pub span: Span, - pub reason: UnsupportedLiteralReason, - pub is_bytestr: bool, - pub start_point_span: Span, -} - -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new( - dcx, - level, - match self.reason { - UnsupportedLiteralReason::Generic => { - fluent::attr_parsing_unsupported_literal_generic - } - UnsupportedLiteralReason::CfgString => { - fluent::attr_parsing_unsupported_literal_cfg_string - } - UnsupportedLiteralReason::CfgBoolean => { - fluent::attr_parsing_unsupported_literal_cfg_boolean - } - }, - ); - diag.span(self.span); - diag.code(E0565); - if self.is_bytestr { - diag.span_suggestion( - self.start_point_span, - fluent::attr_parsing_unsupported_literal_suggestion, - "", - Applicability::MaybeIncorrect, - ); - } - diag - } -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)] pub(crate) struct InvalidReprAlignNeedArg { @@ -375,13 +322,6 @@ pub(crate) struct RustcAllowedUnstablePairing { pub span: Span, } -#[derive(Diagnostic)] -#[diag(attr_parsing_cfg_predicate_identifier)] -pub(crate) struct CfgPredicateIdentifier { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_deprecated_item_suggestion)] pub(crate) struct DeprecatedItemSuggestion { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a0bee4e182147..ac5b3c2407851 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -167,7 +167,7 @@ pub(crate) fn compile_fn( context.clear(); context.func = codegened_func.func; - #[cfg(any())] // This is never true + #[cfg(false)] let _clif_guard = { use std::fmt::Write; diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 561230c193ce2..ab937d4a012c8 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -7,9 +7,7 @@ use std::cell::{Ref, RefCell}; use std::ops::Deref; -use std::slice::from_ref; -use hir::Expr; use hir::def::DefKind; use hir::pat_util::EnumerateAndAdjustIterator as _; use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; @@ -313,7 +311,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let param_place = self.cat_rvalue(param.hir_id, param_ty); - self.walk_irrefutable_pat(¶m_place, param.pat)?; + self.fake_read_scrutinee(¶m_place, false)?; + self.walk_pat(¶m_place, param.pat, false)?; } self.consume_expr(body.value)?; @@ -455,13 +454,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx hir::ExprKind::Match(discr, arms, _) => { let discr_place = self.cat_expr(discr)?; - self.maybe_read_scrutinee( - discr, - discr_place.clone(), - arms.iter().map(|arm| arm.pat), - )?; + self.fake_read_scrutinee(&discr_place, true)?; + self.walk_expr(discr)?; - // treatment of the discriminant is handled while walking the arms. for arm in arms { self.walk_arm(&discr_place, arm)?; } @@ -598,116 +593,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } - fn maybe_read_scrutinee<'t>( + #[instrument(skip(self), level = "debug")] + fn fake_read_scrutinee( &self, - discr: &Expr<'_>, - discr_place: PlaceWithHirId<'tcx>, - pats: impl Iterator>, + discr_place: &PlaceWithHirId<'tcx>, + refutable: bool, ) -> Result<(), Cx::Error> { - // Matching should not always be considered a use of the place, hence - // discr does not necessarily need to be borrowed. - // We only want to borrow discr if the pattern contain something other - // than wildcards. - let mut needs_to_be_read = false; - for pat in pats { - self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { - match &pat.kind { - PatKind::Missing => unreachable!(), - PatKind::Binding(.., opt_sub_pat) => { - // If the opt_sub_pat is None, then the binding does not count as - // a wildcard for the purpose of borrowing discr. - if opt_sub_pat.is_none() { - needs_to_be_read = true; - } - } - PatKind::Never => { - // A never pattern reads the value. - // FIXME(never_patterns): does this do what I expect? - needs_to_be_read = true; - } - PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => { - // A `Path` pattern is just a name like `Foo`. This is either a - // named constant or else it refers to an ADT variant - - let res = self.cx.typeck_results().qpath_res(qpath, *hir_id); - match res { - Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { - // Named constants have to be equated with the value - // being matched, so that's a read of the value being matched. - // - // FIXME: We don't actually reads for ZSTs. - needs_to_be_read = true; - } - _ => { - // Otherwise, this is a struct/enum variant, and so it's - // only a read if we need to read the discriminant. - needs_to_be_read |= - self.is_multivariant_adt(place.place.ty(), *span); - } - } - } - PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => { - // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching - // against a multivariant enum or struct. In that case, we have to read - // the discriminant. Otherwise this kind of pattern doesn't actually - // read anything (we'll get invoked for the `...`, which may indeed - // perform some reads). - - let place_ty = place.place.ty(); - needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span); - } - PatKind::Expr(_) | PatKind::Range(..) => { - // If the PatKind is a Lit or a Range then we want - // to borrow discr. - needs_to_be_read = true; - } - PatKind::Slice(lhs, wild, rhs) => { - // We don't need to test the length if the pattern is `[..]` - if matches!((lhs, wild, rhs), (&[], Some(_), &[])) - // Arrays have a statically known size, so - // there is no need to read their length - || place.place.ty().peel_refs().is_array() - { - } else { - needs_to_be_read = true; - } - } - PatKind::Or(_) - | PatKind::Box(_) - | PatKind::Deref(_) - | PatKind::Ref(..) - | PatKind::Guard(..) - | PatKind::Wild - | PatKind::Err(_) => { - // If the PatKind is Or, Box, or Ref, the decision is made later - // as these patterns contains subpatterns - // If the PatKind is Wild or Err, the decision is made based on the other patterns - // being examined - } - } - - Ok(()) - })? - } + let closure_def_id = match discr_place.place.base { + PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id), + _ => None, + }; - if needs_to_be_read { - self.borrow_expr(discr, BorrowKind::Immutable)?; + let cause = if refutable { + FakeReadCause::ForMatchedPlace(closure_def_id) } else { - let closure_def_id = match discr_place.place.base { - PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id), - _ => None, - }; + FakeReadCause::ForLet(closure_def_id) + }; - self.delegate.borrow_mut().fake_read( - &discr_place, - FakeReadCause::ForMatchedPlace(closure_def_id), - discr_place.hir_id, - ); + self.delegate.borrow_mut().fake_read(discr_place, cause, discr_place.hir_id); - // We always want to walk the discriminant. We want to make sure, for instance, - // that the discriminant has been initialized. - self.walk_expr(discr)?; - } Ok(()) } @@ -724,12 +628,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.walk_expr(expr)?; let expr_place = self.cat_expr(expr)?; f()?; + self.fake_read_scrutinee(&expr_place, els.is_some())?; + self.walk_pat(&expr_place, pat, false)?; if let Some(els) = els { - // borrowing because we need to test the discriminant - self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?; self.walk_block(els)?; } - self.walk_irrefutable_pat(&expr_place, pat)?; Ok(()) } @@ -901,16 +804,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>, ) -> Result<(), Cx::Error> { - let closure_def_id = match discr_place.place.base { - PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id), - _ => None, - }; - - self.delegate.borrow_mut().fake_read( - discr_place, - FakeReadCause::ForMatchedPlace(closure_def_id), - discr_place.hir_id, - ); self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?; if let Some(ref e) = arm.guard { @@ -921,28 +814,20 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } - /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or - /// let binding, and *not* a match arm or nested pat.) - fn walk_irrefutable_pat( - &self, - discr_place: &PlaceWithHirId<'tcx>, - pat: &hir::Pat<'_>, - ) -> Result<(), Cx::Error> { - let closure_def_id = match discr_place.place.base { - PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id), - _ => None, - }; - - self.delegate.borrow_mut().fake_read( - discr_place, - FakeReadCause::ForLet(closure_def_id), - discr_place.hir_id, - ); - self.walk_pat(discr_place, pat, false)?; - Ok(()) - } - /// The core driver for walking a pattern + /// + /// This should mirror how pattern-matching gets lowered to MIR, as + /// otherwise lowering will ICE when trying to resolve the upvars. + /// + /// However, it is okay to approximate it here by doing *more* accesses than + /// the actual MIR builder will, which is useful when some checks are too + /// cumbersome to perform here. For example, if after typeck it becomes + /// clear that only one variant of an enum is inhabited, and therefore a + /// read of the discriminant is not necessary, `walk_pat` will have + /// over-approximated the necessary upvar capture granularity. + /// + /// Do note that discrepancies like these do still create obscure corners + /// in the semantics of the language, and should be avoided if possible. #[instrument(skip(self), level = "debug")] fn walk_pat( &self, @@ -952,6 +837,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ) -> Result<(), Cx::Error> { let tcx = self.cx.tcx(); self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { + debug!("walk_pat: pat.kind={:?}", pat.kind); + let read_discriminant = || { + self.delegate.borrow_mut().borrow(place, discr_place.hir_id, BorrowKind::Immutable); + }; + match pat.kind { PatKind::Binding(_, canonical_id, ..) => { debug!("walk_pat: binding place={:?} pat={:?}", place, pat); @@ -974,11 +864,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // binding when lowering pattern guards to ensure that the guard does not // modify the scrutinee. if has_guard { - self.delegate.borrow_mut().borrow( - place, - discr_place.hir_id, - BorrowKind::Immutable, - ); + read_discriminant(); } // It is also a borrow or copy/move of the value being matched. @@ -1014,13 +900,73 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx PatKind::Never => { // A `!` pattern always counts as an immutable read of the discriminant, // even in an irrefutable pattern. - self.delegate.borrow_mut().borrow( - place, - discr_place.hir_id, - BorrowKind::Immutable, - ); + read_discriminant(); + } + PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => { + // A `Path` pattern is just a name like `Foo`. This is either a + // named constant or else it refers to an ADT variant + + let res = self.cx.typeck_results().qpath_res(qpath, *hir_id); + match res { + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { + // Named constants have to be equated with the value + // being matched, so that's a read of the value being matched. + // + // FIXME: Does the MIR code skip this read when matching on a ZST? + // If so, we can also skip it here. + read_discriminant(); + } + _ => { + // Otherwise, this is a struct/enum variant, and so it's + // only a read if we need to read the discriminant. + if self.is_multivariant_adt(place.place.ty(), *span) { + read_discriminant(); + } + } + } + } + PatKind::Expr(_) | PatKind::Range(..) => { + // When matching against a literal or range, we need to + // borrow the place to compare it against the pattern. + // + // Note that we do this read even if the range matches all + // possible values, such as 0..=u8::MAX. This is because + // we don't want to depend on consteval here. + // + // FIXME: What if the type being matched only has one + // possible value? + read_discriminant(); + } + PatKind::Struct(..) | PatKind::TupleStruct(..) => { + if self.is_multivariant_adt(place.place.ty(), pat.span) { + read_discriminant(); + } + } + PatKind::Slice(lhs, wild, rhs) => { + // We don't need to test the length if the pattern is `[..]` + if matches!((lhs, wild, rhs), (&[], Some(_), &[])) + // Arrays have a statically known size, so + // there is no need to read their length + || place.place.ty().peel_refs().is_array() + { + // No read necessary + } else { + read_discriminant(); + } + } + PatKind::Or(_) + | PatKind::Box(_) + | PatKind::Ref(..) + | PatKind::Guard(..) + | PatKind::Tuple(..) + | PatKind::Wild + | PatKind::Missing + | PatKind::Err(_) => { + // If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses + // are made later as these patterns contains subpatterns. + // If the PatKind is Missing, Wild or Err, any relevant accesses are made when processing + // the other patterns that are part of the match } - _ => {} } Ok(()) @@ -1908,6 +1854,20 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } + /// Checks whether a type has multiple variants, and therefore, whether a + /// read of the discriminant might be necessary. Note that the actual MIR + /// builder code does a more specific check, filtering out variants that + /// happen to be uninhabited. + /// + /// Here, it is not practical to perform such a check, because inhabitedness + /// queries require typeck results, and typeck requires closure capture analysis. + /// + /// Moreover, the language is moving towards uninhabited variants still semantically + /// causing a discriminant read, so we *shouldn't* perform any such check. + /// + /// FIXME(never_patterns): update this comment once the aforementioned MIR builder + /// code is changed to be insensitive to inhhabitedness. + #[instrument(skip(self, span), level = "debug")] fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool { if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() { // Note that if a non-exhaustive SingleVariant is defined in another crate, we need diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 445386412058b..1a2b76485f359 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -761,6 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ], /// } /// ``` + #[instrument(level = "debug", skip(self))] fn compute_min_captures( &self, closure_def_id: LocalDefId, @@ -2029,6 +2030,7 @@ struct InferBorrowKind<'tcx> { } impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { + #[instrument(skip(self), level = "debug")] fn fake_read( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -2119,6 +2121,7 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { } /// Rust doesn't permit moving fields out of a type that implements drop +#[instrument(skip(fcx), ret, level = "debug")] fn restrict_precision_for_drop_types<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, mut place: Place<'tcx>, @@ -2179,6 +2182,7 @@ fn restrict_precision_for_unsafe( /// - No unsafe block is required to capture `place`. /// /// Returns the truncated place and updated capture mode. +#[instrument(ret, level = "debug")] fn restrict_capture_precision( place: Place<'_>, curr_mode: ty::UpvarCapture, @@ -2208,6 +2212,7 @@ fn restrict_capture_precision( } /// Truncate deref of any reference. +#[instrument(ret, level = "debug")] fn adjust_for_move_closure( mut place: Place<'_>, mut kind: ty::UpvarCapture, @@ -2222,6 +2227,7 @@ fn adjust_for_move_closure( } /// Truncate deref of any reference. +#[instrument(ret, level = "debug")] fn adjust_for_use_closure( mut place: Place<'_>, mut kind: ty::UpvarCapture, @@ -2237,6 +2243,7 @@ fn adjust_for_use_closure( /// Adjust closure capture just that if taking ownership of data, only move data /// from enclosing stack frame. +#[instrument(ret, level = "debug")] fn adjust_for_non_move_closure( mut place: Place<'_>, mut kind: ty::UpvarCapture, @@ -2559,6 +2566,7 @@ fn determine_place_ancestry_relation<'tcx>( /// // it is constrained to `'a` /// } /// ``` +#[instrument(ret, level = "debug")] fn truncate_capture_for_optimization( mut place: Place<'_>, mut curr_mode: ty::UpvarCapture, diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 94f638b676e8f..56a0a3ceebf5a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -883,6 +883,7 @@ lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_printl 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_boolean = you may have meant to use `{$literal}` (notice the capitalization). Doing so makes this predicate evaluate to `{$literal}` unconditionally lint_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index e2f5dd315d570..0c8d7523a9dc5 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -138,6 +138,16 @@ pub(super) fn unexpected_cfg_name( let is_from_external_macro = name_span.in_external_macro(sess.source_map()); let mut is_feature_cfg = name == sym::feature; + fn miscapitalized_boolean(name: Symbol) -> Option { + if name.as_str().eq_ignore_ascii_case("false") { + Some(false) + } else if name.as_str().eq_ignore_ascii_case("true") { + Some(true) + } else { + None + } + } + let code_sugg = if is_feature_cfg && is_from_cargo { lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures // Suggest correct `version("..")` predicate syntax @@ -148,6 +158,21 @@ pub(super) fn unexpected_cfg_name( between_name_and_value: name_span.between(value_span), after_value: value_span.shrink_to_hi(), } + // Suggest a literal `false` instead + // Detect miscapitalized `False`/`FALSE` etc, ensuring that this isn't `r#false` + } else if value.is_none() + // If this is a miscapitalized False/FALSE, suggest the boolean literal instead + && let Some(boolean) = miscapitalized_boolean(name) + // Check this isn't a raw identifier + && sess + .source_map() + .span_to_snippet(name_span) + .map_or(true, |snippet| !snippet.contains("r#")) + { + lints::unexpected_cfg_name::CodeSuggestion::BooleanLiteral { + span: name_span, + literal: boolean, + } // 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; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 3978e7e4d34cf..5017ce7caa525 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2401,6 +2401,17 @@ pub(crate) mod unexpected_cfg_name { #[subdiagnostic] expected_names: Option, }, + #[suggestion( + lint_unexpected_cfg_boolean, + applicability = "machine-applicable", + style = "verbose", + code = "{literal}" + )] + BooleanLiteral { + #[primary_span] + span: Span, + literal: bool, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index a0d54354a9c63..67c12bfa7790d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -339,6 +339,12 @@ impl<'tcx> MatchPairTree<'tcx> { if let Some(test_case) = test_case { // This pattern is refutable, so push a new match-pair node. + // + // Note: unless test_case is TestCase::Or, place must not be None. + // This means that the closure capture analysis in + // rustc_hir_typeck::upvar, and in particular the pattern handling + // code of ExprUseVisitor, must capture all of the places we'll use. + // Make sure to keep these two parts in sync! match_pairs.push(MatchPairTree { place, test_case, diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 15ba72bccaa9b..3a4e1e657a3da 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -591,7 +591,7 @@ impl () {} /// # pub unsafe fn malloc(_size: usize) -> *mut core::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() } /// # pub unsafe fn free(_ptr: *mut core::ffi::c_void) {} /// # } -/// # #[cfg(any())] +/// # #[cfg(false)] /// #[allow(unused_extern_crates)] /// extern crate libc; /// diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 40149ee09427c..caf0af35e401d 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -892,8 +892,8 @@ impl Step for Std { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { /// The compiler that will build rustc which will be shipped in this component. - build_compiler: Compiler, - target: TargetSelection, + pub build_compiler: Compiler, + pub target: TargetSelection, } impl RustcDev { diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index d52cc52abbd3e..d23fe029bcc7e 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -279,6 +279,17 @@ install!((self, builder, _config), }); install_sh(builder, "rustc", self.build_compiler, Some(self.target), &tarball); }; + RustcDev, alias = "rustc-dev", Self::should_build(_config), IS_HOST: true, { + if let Some(tarball) = builder.ensure(dist::RustcDev { + build_compiler: self.build_compiler, target: self.target + }) { + install_sh(builder, "rustc-dev", self.build_compiler, Some(self.target), &tarball); + } else { + builder.info( + &format!("skipping Install RustcDev stage{} ({})", self.build_compiler.stage + 1, self.target), + ); + } + }; RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend { compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target), diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 961d0cd855ae3..0bf70883a47ae 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -998,6 +998,7 @@ impl<'a> Builder<'a> { // binary path, we must install rustc before the tools. Otherwise, the rust-installer will // install the same binaries twice for each tool, leaving backup files (*.old) as a result. install::Rustc, + install::RustcDev, install::Cargo, install::RustAnalyzer, install::Rustfmt, diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 709d646bb359a..9146c470e358a 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2912,6 +2912,7 @@ mod snapshot { [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc + [dist] rustc 1 -> rustc-dev 2 [build] rustc 1 -> cargo 2 [dist] rustc 1 -> cargo 2 [build] rustc 1 -> rust-analyzer 2 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 78b81b5b74d69..6f666caf306f0 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,7 +6,83 @@ document. ## Unreleased / Beta / In Rust Nightly -[e9b7045...master](https://github.com/rust-lang/rust-clippy/compare/e9b7045...master) +[d9fb15c...master](https://github.com/rust-lang/rust-clippy/compare/d9fb15c...master) + +## Rust 1.92 + +Current stable, released 2025-12-11 + +[View all 124 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-09-05T18%3A24%3A03Z..2025-10-16T14%3A13%3A43Z+base%3Amaster) + +### New Lints + +* Added [`unnecessary_option_map_or_else`] to `suspicious` + [#14662](https://github.com/rust-lang/rust-clippy/pull/14662) +* Added [`replace_box`] to `perf` + [#14953](https://github.com/rust-lang/rust-clippy/pull/14953) +* Added [`volatile_composites`] to `nursery` + [#15686](https://github.com/rust-lang/rust-clippy/pull/15686) +* Added [`self_only_used_in_recursion`] to `pedantic` + [#14787](https://github.com/rust-lang/rust-clippy/pull/14787) +* Added [`redundant_iter_cloned`] to `perf` + [#15277](https://github.com/rust-lang/rust-clippy/pull/15277) + +### Moves and Deprecations + +* Renamed [`unchecked_duration_subtraction`] to [`unchecked_time_subtraction`] + [#13800](https://github.com/rust-lang/rust-clippy/pull/13800) + +### Enhancements + +* [`mutex_atomic`] and [`mutex_integer`] overhauled to only lint definitions, not uses; added suggestions + and better help messages + [#15632](https://github.com/rust-lang/rust-clippy/pull/15632) +* [`manual_rotate`] now recognizes non-const rotation amounts + [#15402](https://github.com/rust-lang/rust-clippy/pull/15402) +* [`multiple_inherent_impl`] added `inherent-impl-lint-scope` config option (`module`, `file`, + or `crate`) + [#15843](https://github.com/rust-lang/rust-clippy/pull/15843) +* [`use_self`] now checks structs and enums + [#15566](https://github.com/rust-lang/rust-clippy/pull/15566) +* [`while_let_loop`] extended to lint on `loop { let else }` + [#15701](https://github.com/rust-lang/rust-clippy/pull/15701) +* [`mut_mut`] overhauled with structured suggestions and improved documentation + [#15417](https://github.com/rust-lang/rust-clippy/pull/15417) +* [`nonstandard_macro_braces`] now suggests trailing semicolon when needed + [#15593](https://github.com/rust-lang/rust-clippy/pull/15593) +* [`ptr_offset_with_cast`] now respects MSRV when suggesting fix, and lints more cases + [#15613](https://github.com/rust-lang/rust-clippy/pull/15613) +* [`cast_sign_loss`] and [`cast_possible_wrap`] added suggestions using `cast_{un,}signed()` methods + (MSRV 1.87+) + [#15384](https://github.com/rust-lang/rust-clippy/pull/15384) +* [`unchecked_time_subtraction`] extended to include `Duration - Duration` operations + [#13800](https://github.com/rust-lang/rust-clippy/pull/13800) +* [`filter_next`] now suggests replacing `filter().next_back()` with `rfind()` for + `DoubleEndedIterator` + [#15748](https://github.com/rust-lang/rust-clippy/pull/15748) + +### False Positive Fixes + +* [`unnecessary_safety_comment`] fixed FPs with comments above attributes + [#15678](https://github.com/rust-lang/rust-clippy/pull/15678) +* [`manual_unwrap_or`] fixed FP edge case + [#15812](https://github.com/rust-lang/rust-clippy/pull/15812) +* [`needless_continue`] fixed FP when match type is not unit or never + [#15547](https://github.com/rust-lang/rust-clippy/pull/15547) +* [`if_then_some_else_none`] fixed FP when return exists in block expr + [#15783](https://github.com/rust-lang/rust-clippy/pull/15783) +* [`new_without_default`] fixed to copy `#[cfg]` onto `impl Default` and fixed FP on private type + with trait impl + [#15720](https://github.com/rust-lang/rust-clippy/pull/15720) + [#15782](https://github.com/rust-lang/rust-clippy/pull/15782) +* [`question_mark`] fixed FP on variables used after + [#15644](https://github.com/rust-lang/rust-clippy/pull/15644) +* [`needless_return`] fixed FP with `cfg`d code after `return` + [#15669](https://github.com/rust-lang/rust-clippy/pull/15669) +* [`useless_attribute`] fixed FP on `deprecated_in_future` + [#15645](https://github.com/rust-lang/rust-clippy/pull/15645) +* [`double_parens`] fixed FP when macros are involved + [#15420](https://github.com/rust-lang/rust-clippy/pull/15420) ## Rust 1.91 @@ -6280,6 +6356,7 @@ Released 2018-09-13 [`cyclomatic_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cyclomatic_complexity [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call +[`decimal_bitwise_operands`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_bitwise_operands [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const [`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs @@ -6541,6 +6618,7 @@ Released 2018-09-13 [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one [`manual_ignore_case_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ignore_case_cmp +[`manual_ilog2`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ilog2 [`manual_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check @@ -6686,6 +6764,7 @@ Released 2018-09-13 [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return [`needless_return_with_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return_with_question_mark [`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn +[`needless_type_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_type_cast [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update [`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord [`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply @@ -6765,6 +6844,7 @@ Released 2018-09-13 [`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr [`ptr_cast_constness`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_cast_constness [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq +[`ptr_offset_by_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_by_literal [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names [`pub_underscore_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields @@ -7081,6 +7161,7 @@ Released 2018-09-13 [`allow-expect-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-consts [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests [`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests +[`allow-large-stack-frames-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-large-stack-frames-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 diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index fee885d8fa7e9..67078adea2b47 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.93" +version = "0.1.94" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 20a5e997e629b..78498c73ae786 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -4,7 +4,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 800 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md index 5d2c3972b060a..c5b264c9f703c 100644 --- a/src/tools/clippy/book/src/README.md +++ b/src/tools/clippy/book/src/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 800 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 2e185fb3a086e..a1c079898594f 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -111,6 +111,16 @@ Whether `indexing_slicing` should be allowed in test functions or `#[cfg(test)]` * [`indexing_slicing`](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) +## `allow-large-stack-frames-in-tests` +Whether functions inside `#[cfg(test)]` modules or test functions should be checked. + +**Default Value:** `true` + +--- +**Affected lints:** +* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames) + + ## `allow-mixed-uninlined-format-args` Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index 3f6b26d3334ed..a65fe7bcbda58 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.93" +version = "0.1.94" edition = "2024" publish = false diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 2e9cf8e91f7d0..e1d7c1d88eb9a 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -373,6 +373,9 @@ define_Conf! { /// Whether `indexing_slicing` should be allowed in test functions or `#[cfg(test)]` #[lints(indexing_slicing)] allow_indexing_slicing_in_tests: bool = false, + /// Whether functions inside `#[cfg(test)]` modules or test functions should be checked. + #[lints(large_stack_frames)] + allow_large_stack_frames_in_tests: bool = true, /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` #[lints(uninlined_format_args)] allow_mixed_uninlined_format_args: bool = true, diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index bc97746a1cbae..7a78ef32bf3c2 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.93" +version = "0.1.94" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index 47cc1da0a6e9f..494d6180d3cb1 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -19,6 +19,7 @@ mod fn_to_numeric_cast; mod fn_to_numeric_cast_any; mod fn_to_numeric_cast_with_truncation; mod manual_dangling_ptr; +mod needless_type_cast; mod ptr_as_ptr; mod ptr_cast_constness; mod ref_as_ptr; @@ -813,6 +814,32 @@ declare_clippy_lint! { "casting a primitive method pointer to any integer type" } +declare_clippy_lint! { + /// ### What it does + /// Checks for bindings (constants, statics, or let bindings) that are defined + /// with one numeric type but are consistently cast to a different type in all usages. + /// + /// ### Why is this bad? + /// If a binding is always cast to a different type when used, it would be clearer + /// and more efficient to define it with the target type from the start. + /// + /// ### Example + /// ```no_run + /// const SIZE: u16 = 15; + /// let arr: [u8; SIZE as usize] = [0; SIZE as usize]; + /// ``` + /// + /// Use instead: + /// ```no_run + /// const SIZE: usize = 15; + /// let arr: [u8; SIZE] = [0; SIZE]; + /// ``` + #[clippy::version = "1.93.0"] + pub NEEDLESS_TYPE_CAST, + pedantic, + "binding defined with one type but always cast to another" +} + pub struct Casts { msrv: Msrv, } @@ -851,6 +878,7 @@ impl_lint_pass!(Casts => [ AS_POINTER_UNDERSCORE, MANUAL_DANGLING_PTR, CONFUSING_METHOD_TO_NUMERIC_CAST, + NEEDLESS_TYPE_CAST, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -920,4 +948,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_slice_different_sizes::check(cx, expr, self.msrv); ptr_cast_constness::check_null_ptr_cast_method(cx, expr); } + + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &rustc_hir::Body<'tcx>) { + needless_type_cast::check(cx, body); + } } diff --git a/src/tools/clippy/clippy_lints/src/casts/needless_type_cast.rs b/src/tools/clippy/clippy_lints/src/casts/needless_type_cast.rs new file mode 100644 index 0000000000000..ca6aa0f87bbf3 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/casts/needless_type_cast.rs @@ -0,0 +1,289 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::visitors::{Descend, for_each_expr, for_each_expr_without_closures}; +use core::ops::ControlFlow; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{BlockCheckMode, Body, Expr, ExprKind, HirId, LetStmt, PatKind, StmtKind, UnsafeSource}; +use rustc_lint::LateContext; +use rustc_middle::ty::{Ty, TypeVisitableExt}; +use rustc_span::Span; + +use super::NEEDLESS_TYPE_CAST; + +struct BindingInfo<'a> { + source_ty: Ty<'a>, + ty_span: Span, +} + +struct UsageInfo<'a> { + cast_to: Option>, + in_generic_context: bool, +} + +pub(super) fn check<'a>(cx: &LateContext<'a>, body: &Body<'a>) { + let mut bindings: FxHashMap> = FxHashMap::default(); + + for_each_expr_without_closures(body.value, |expr| { + match expr.kind { + ExprKind::Block(block, _) => { + for stmt in block.stmts { + if let StmtKind::Let(let_stmt) = stmt.kind { + collect_binding_from_local(cx, let_stmt, &mut bindings); + } + } + }, + ExprKind::Let(let_expr) => { + collect_binding_from_let(cx, let_expr, &mut bindings); + }, + _ => {}, + } + ControlFlow::<()>::Continue(()) + }); + + #[allow(rustc::potential_query_instability)] + let mut binding_vec: Vec<_> = bindings.into_iter().collect(); + binding_vec.sort_by_key(|(_, info)| info.ty_span.lo()); + + for (hir_id, binding_info) in binding_vec { + check_binding_usages(cx, body, hir_id, &binding_info); + } +} + +fn collect_binding_from_let<'a>( + cx: &LateContext<'a>, + let_expr: &rustc_hir::LetExpr<'a>, + bindings: &mut FxHashMap>, +) { + if let_expr.ty.is_none() + || let_expr.span.from_expansion() + || has_generic_return_type(cx, let_expr.init) + || contains_unsafe(let_expr.init) + { + return; + } + + if let PatKind::Binding(_, hir_id, _, _) = let_expr.pat.kind + && let Some(ty_hir) = let_expr.ty + { + let ty = cx.typeck_results().pat_ty(let_expr.pat); + if ty.is_numeric() { + bindings.insert( + hir_id, + BindingInfo { + source_ty: ty, + ty_span: ty_hir.span, + }, + ); + } + } +} + +fn collect_binding_from_local<'a>( + cx: &LateContext<'a>, + let_stmt: &LetStmt<'a>, + bindings: &mut FxHashMap>, +) { + if let_stmt.ty.is_none() + || let_stmt.span.from_expansion() + || let_stmt + .init + .is_some_and(|init| has_generic_return_type(cx, init) || contains_unsafe(init)) + { + return; + } + + if let PatKind::Binding(_, hir_id, _, _) = let_stmt.pat.kind + && let Some(ty_hir) = let_stmt.ty + { + let ty = cx.typeck_results().pat_ty(let_stmt.pat); + if ty.is_numeric() { + bindings.insert( + hir_id, + BindingInfo { + source_ty: ty, + ty_span: ty_hir.span, + }, + ); + } + } +} + +fn contains_unsafe(expr: &Expr<'_>) -> bool { + for_each_expr_without_closures(expr, |e| { + if let ExprKind::Block(block, _) = e.kind + && let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules + { + return ControlFlow::Break(()); + } + ControlFlow::Continue(()) + }) + .is_some() +} + +fn has_generic_return_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match &expr.kind { + ExprKind::Block(block, _) => { + if let Some(tail_expr) = block.expr { + return has_generic_return_type(cx, tail_expr); + } + false + }, + ExprKind::If(_, then_block, else_expr) => { + has_generic_return_type(cx, then_block) || else_expr.is_some_and(|e| has_generic_return_type(cx, e)) + }, + ExprKind::Match(_, arms, _) => arms.iter().any(|arm| has_generic_return_type(cx, arm.body)), + ExprKind::Loop(block, label, ..) => for_each_expr_without_closures(*block, |e| { + match e.kind { + ExprKind::Loop(..) => { + // Unlabeled breaks inside nested loops target the inner loop, not ours + return ControlFlow::Continue(Descend::No); + }, + ExprKind::Break(dest, Some(break_expr)) => { + let targets_this_loop = + dest.label.is_none() || dest.label.map(|l| l.ident) == label.map(|l| l.ident); + if targets_this_loop && has_generic_return_type(cx, break_expr) { + return ControlFlow::Break(()); + } + }, + _ => {}, + } + ControlFlow::Continue(Descend::Yes) + }) + .is_some(), + ExprKind::MethodCall(..) => { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); + let ret_ty = sig.output().skip_binder(); + return ret_ty.has_param(); + } + false + }, + ExprKind::Call(callee, _) => { + if let ExprKind::Path(qpath) = &callee.kind { + let res = cx.qpath_res(qpath, callee.hir_id); + if let Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) = res { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); + let ret_ty = sig.output().skip_binder(); + return ret_ty.has_param(); + } + } + false + }, + _ => false, + } +} + +fn is_generic_res(cx: &LateContext<'_>, res: Res) -> bool { + let has_type_params = |def_id| { + cx.tcx + .generics_of(def_id) + .own_params + .iter() + .any(|p| p.kind.is_ty_or_const()) + }; + match res { + Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => has_type_params(def_id), + // Ctor → Variant → ADT: constructor's parent is variant, variant's parent is the ADT + Res::Def(DefKind::Ctor(..), def_id) => has_type_params(cx.tcx.parent(cx.tcx.parent(def_id))), + _ => false, + } +} + +fn is_cast_in_generic_context<'a>(cx: &LateContext<'a>, cast_expr: &Expr<'a>) -> bool { + let mut current_id = cast_expr.hir_id; + + loop { + let parent_id = cx.tcx.parent_hir_id(current_id); + if parent_id == current_id { + return false; + } + + let parent = cx.tcx.hir_node(parent_id); + + match parent { + rustc_hir::Node::Expr(parent_expr) => { + match &parent_expr.kind { + ExprKind::Closure(_) => return false, + ExprKind::Call(callee, _) => { + if let ExprKind::Path(qpath) = &callee.kind { + let res = cx.qpath_res(qpath, callee.hir_id); + if is_generic_res(cx, res) { + return true; + } + } + }, + ExprKind::MethodCall(..) => { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) + && cx + .tcx + .generics_of(def_id) + .own_params + .iter() + .any(|p| p.kind.is_ty_or_const()) + { + return true; + } + }, + _ => {}, + } + current_id = parent_id; + }, + _ => return false, + } + } +} + +fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) { + let mut usages = Vec::new(); + + for_each_expr(cx, body.value, |expr| { + if let ExprKind::Path(ref qpath) = expr.kind + && !expr.span.from_expansion() + && let Res::Local(id) = cx.qpath_res(qpath, expr.hir_id) + && id == hir_id + { + let parent_id = cx.tcx.parent_hir_id(expr.hir_id); + let parent = cx.tcx.hir_node(parent_id); + + let usage = if let rustc_hir::Node::Expr(parent_expr) = parent + && let ExprKind::Cast(..) = parent_expr.kind + && !parent_expr.span.from_expansion() + { + UsageInfo { + cast_to: Some(cx.typeck_results().expr_ty(parent_expr)), + in_generic_context: is_cast_in_generic_context(cx, parent_expr), + } + } else { + UsageInfo { + cast_to: None, + in_generic_context: false, + } + }; + usages.push(usage); + } + ControlFlow::<()>::Continue(()) + }); + + let Some(first_target) = usages + .first() + .and_then(|u| u.cast_to) + .filter(|&t| t != binding_info.source_ty) + .filter(|&t| usages.iter().all(|u| u.cast_to == Some(t) && !u.in_generic_context)) + else { + return; + }; + + span_lint_and_sugg( + cx, + NEEDLESS_TYPE_CAST, + binding_info.ty_span, + format!( + "this binding is defined as `{}` but is always cast to `{}`", + binding_info.source_ty, first_target + ), + "consider defining it as", + first_target.to_string(), + Applicability::MaybeIncorrect, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 4a350dca2993b..87d75234ebc01 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -70,6 +70,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO, crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO, crate::casts::MANUAL_DANGLING_PTR_INFO, + crate::casts::NEEDLESS_TYPE_CAST_INFO, crate::casts::PTR_AS_PTR_INFO, crate::casts::PTR_CAST_CONSTNESS_INFO, crate::casts::REF_AS_PTR_INFO, @@ -245,8 +246,8 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, crate::large_stack_frames::LARGE_STACK_FRAMES_INFO, crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO, + crate::len_without_is_empty::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, - crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::LEN_ZERO_INFO, crate::let_if_seq::USELESS_LET_IF_SEQ_INFO, crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO, @@ -300,6 +301,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_ignore_case_cmp::MANUAL_IGNORE_CASE_CMP_INFO, + crate::manual_ilog2::MANUAL_ILOG2_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_is_power_of_two::MANUAL_IS_POWER_OF_TWO_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, @@ -444,6 +446,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::OR_THEN_UNWRAP_INFO, crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO, crate::methods::PATH_ENDS_WITH_EXT_INFO, + crate::methods::PTR_OFFSET_BY_LITERAL_INFO, crate::methods::PTR_OFFSET_WITH_CAST_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, crate::methods::READONLY_WRITE_LOCK_INFO, @@ -578,6 +581,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::operators::ASSIGN_OP_PATTERN_INFO, crate::operators::BAD_BIT_MASK_INFO, crate::operators::CMP_OWNED_INFO, + crate::operators::DECIMAL_BITWISE_OPERANDS_INFO, crate::operators::DOUBLE_COMPARISONS_INFO, crate::operators::DURATION_SUBSEC_INFO, crate::operators::EQ_OP_INFO, diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index f010d17917f9e..6e62e983d2f31 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -34,7 +34,7 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ #[clippy::version = "pre 1.29.0"] ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), #[clippy::version = "1.91.0"] - ("clippy::string_to_string", "`clippy:implicit_clone` covers those cases"), + ("clippy::string_to_string", "`clippy::implicit_clone` covers those cases"), #[clippy::version = "pre 1.29.0"] ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"), #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index a5ec6777b4344..bdfe2e49e66e1 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -3,11 +3,12 @@ use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_appl use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, - peel_hir_expr_while, + SpanlessEq, can_move_expr_to_closure_no_visit, desugar_await, higher, is_expr_final_block_expr, + is_expr_used_or_unified, paths, peel_hir_expr_while, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; @@ -382,6 +383,8 @@ struct InsertSearcher<'cx, 'tcx> { loops: Vec, /// Local variables created in the expression. These don't need to be captured. locals: HirIdSet, + /// Whether the map is a non-async-aware `MutexGuard`. + map_is_mutex_guard: bool, } impl<'tcx> InsertSearcher<'_, 'tcx> { /// Visit the expression as a branch in control flow. Multiple insert calls can be used, but @@ -524,15 +527,22 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { ExprKind::If(cond_expr, then_expr, Some(else_expr)) => { self.is_single_insert = false; self.visit_non_tail_expr(cond_expr); - // Each branch may contain it's own insert expression. + // Each branch may contain its own insert expression. let mut is_map_used = self.visit_cond_arm(then_expr); is_map_used |= self.visit_cond_arm(else_expr); self.is_map_used = is_map_used; }, ExprKind::Match(scrutinee_expr, arms, _) => { + // If the map is a non-async-aware `MutexGuard` and + // `.await` expression appears alongside map insertion in the same `then` or `else` block, + // we cannot suggest using `entry()` because it would hold the lock across the await point, + // triggering `await_holding_lock` and risking deadlock. + if self.map_is_mutex_guard && desugar_await(expr).is_some() { + self.can_use_entry = false; + } self.is_single_insert = false; self.visit_non_tail_expr(scrutinee_expr); - // Each branch may contain it's own insert expression. + // Each branch may contain its own insert expression. let mut is_map_used = self.is_map_used; for arm in arms { self.visit_pat(arm.pat); @@ -725,16 +735,32 @@ fn find_insert_calls<'tcx>( edits: Vec::new(), loops: Vec::new(), locals: HirIdSet::default(), + map_is_mutex_guard: false, }; + // Check if the map is a non-async-aware `MutexGuard` + if let rustc_middle::ty::Adt(adt, _) = cx.typeck_results().expr_ty(contains_expr.map).kind() + && is_mutex_guard(cx, adt.did()) + { + s.map_is_mutex_guard = true; + } + s.visit_expr(expr); - let allow_insert_closure = s.allow_insert_closure; - let is_single_insert = s.is_single_insert; + if !s.can_use_entry { + return None; + } + let is_key_used_and_no_copy = s.is_key_used && !is_copy(cx, cx.typeck_results().expr_ty(contains_expr.key)); - let edits = s.edits; - s.can_use_entry.then_some(InsertSearchResults { - edits, - allow_insert_closure, - is_single_insert, + Some(InsertSearchResults { + edits: s.edits, + allow_insert_closure: s.allow_insert_closure, + is_single_insert: s.is_single_insert, is_key_used_and_no_copy, }) } + +fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { + match cx.tcx.get_diagnostic_name(def_id) { + Some(name) => matches!(name, sym::MutexGuard | sym::RwLockReadGuard | sym::RwLockWriteGuard), + None => paths::PARKING_LOT_GUARDS.iter().any(|guard| guard.matches(cx, def_id)), + } +} diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs index 5ed948c02bbcc..6b0080d04c447 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs @@ -2,15 +2,16 @@ use std::{fmt, ops}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::fn_has_unsatisfiable_preds; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::{HasSession, SpanRangeExt}; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_in_test}; +use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lexer::is_ident; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -83,12 +84,14 @@ declare_clippy_lint! { pub struct LargeStackFrames { maximum_allowed_size: u64, + allow_large_stack_frames_in_tests: bool, } impl LargeStackFrames { pub fn new(conf: &'static Conf) -> Self { Self { maximum_allowed_size: conf.stack_size_threshold, + allow_large_stack_frames_in_tests: conf.allow_large_stack_frames_in_tests, } } } @@ -152,67 +155,122 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { let mir = cx.tcx.optimized_mir(def_id); let typing_env = mir.typing_env(cx.tcx); - let sizes_of_locals = || { - mir.local_decls.iter().filter_map(|local| { + let sizes_of_locals = mir + .local_decls + .iter() + .filter_map(|local| { let layout = cx.tcx.layout_of(typing_env.as_query_input(local.ty)).ok()?; Some((local, layout.size.bytes())) }) - }; + .collect::>(); - let frame_size = sizes_of_locals().fold(Space::Used(0), |sum, (_, size)| sum + size); + let frame_size = sizes_of_locals + .iter() + .fold(Space::Used(0), |sum, (_, size)| sum + *size); let limit = self.maximum_allowed_size; if frame_size.exceeds_limit(limit) { // Point at just the function name if possible, because lints that span // the entire body and don't have to are less legible. - let fn_span = match fn_kind { - FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, - FnKind::Closure => entire_fn_span, + let (fn_span, fn_name) = match fn_kind { + FnKind::ItemFn(ident, _, _) => (ident.span, format!("function `{}`", ident.name)), + FnKind::Method(ident, _) => (ident.span, format!("method `{}`", ident.name)), + FnKind::Closure => (entire_fn_span, "closure".to_string()), }; + // Don't lint inside tests if configured to not do so. + if self.allow_large_stack_frames_in_tests && is_in_test(cx.tcx, cx.tcx.local_def_id_to_hir_id(local_def_id)) + { + return; + } + + let explain_lint = |diag: &mut Diag<'_, ()>, ctxt: SyntaxContext| { + // Point out the largest individual contribution to this size, because + // it is the most likely to be unintentionally large. + if let Some((local, size)) = sizes_of_locals.iter().max_by_key(|&(_, size)| size) + && let local_span = local.source_info.span + && local_span.ctxt() == ctxt + { + let size = Space::Used(*size); // pluralizes for us + let ty = local.ty; + + // TODO: Is there a cleaner, robust way to ask this question? + // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", + // and that doesn't get us the true name in scope rather than the span text either. + if let Some(name) = local_span.get_source_text(cx) + && is_ident(&name) + { + // If the local is an ordinary named variable, + // print its name rather than relying solely on the span. + diag.span_label( + local_span, + format!("`{name}` is the largest part, at {size} for type `{ty}`"), + ); + } else { + diag.span_label( + local_span, + format!("this is the largest part, at {size} for type `{ty}`"), + ); + } + } + + // Explain why we are linting this and not other functions. + diag.note(format!( + "{frame_size} is larger than Clippy's configured `stack-size-threshold` of {limit}" + )); + + // Explain why the user should care, briefly. + diag.note_once( + "allocating large amounts of stack space can overflow the stack \ + and cause the program to abort", + ); + }; + + if fn_span.from_expansion() { + // Don't lint on the main function generated by `--test` target + if cx.sess().is_test_crate() && is_entrypoint_fn(cx, local_def_id.to_def_id()) { + return; + } + + let is_from_external_macro = fn_span.in_external_macro(cx.sess().source_map()); + span_lint_and_then( + cx, + LARGE_STACK_FRAMES, + fn_span.source_callsite(), + format!( + "{} generated by this macro may allocate a lot of stack space", + if is_from_external_macro { + cx.tcx.def_descr(local_def_id.into()) + } else { + fn_name.as_str() + } + ), + |diag| { + if is_from_external_macro { + return; + } + + diag.span_label( + fn_span, + format!( + "this {} has a stack frame size of {frame_size}", + cx.tcx.def_descr(local_def_id.into()) + ), + ); + + explain_lint(diag, fn_span.ctxt()); + }, + ); + return; + } + span_lint_and_then( cx, LARGE_STACK_FRAMES, fn_span, format!("this function may allocate {frame_size} on the stack"), |diag| { - // Point out the largest individual contribution to this size, because - // it is the most likely to be unintentionally large. - if let Some((local, size)) = sizes_of_locals().max_by_key(|&(_, size)| size) { - let local_span: Span = local.source_info.span; - let size = Space::Used(size); // pluralizes for us - let ty = local.ty; - - // TODO: Is there a cleaner, robust way to ask this question? - // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", - // and that doesn't get us the true name in scope rather than the span text either. - if let Some(name) = local_span.get_source_text(cx) - && is_ident(&name) - { - // If the local is an ordinary named variable, - // print its name rather than relying solely on the span. - diag.span_label( - local_span, - format!("`{name}` is the largest part, at {size} for type `{ty}`"), - ); - } else { - diag.span_label( - local_span, - format!("this is the largest part, at {size} for type `{ty}`"), - ); - } - } - - // Explain why we are linting this and not other functions. - diag.note(format!( - "{frame_size} is larger than Clippy's configured `stack-size-threshold` of {limit}" - )); - - // Explain why the user should care, briefly. - diag.note_once( - "allocating large amounts of stack space can overflow the stack \ - and cause the program to abort", - ); + explain_lint(diag, SyntaxContext::root()); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs new file mode 100644 index 0000000000000..1d219d7c3b74d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs @@ -0,0 +1,342 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::res::MaybeDef; +use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, sym}; +use rustc_hir::def::Res; +use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_hir::{ + FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, + Node, OpaqueTyOrigin, PathSegment, PrimTy, QPath, TraitItemId, TyKind, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, FnSig, Ty}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::kw; +use rustc_span::{Ident, Span, Symbol}; +use rustc_trait_selection::traits::supertrait_def_ids; + +declare_clippy_lint! { + /// ### What it does + /// Checks for items that implement `.len()` but not + /// `.is_empty()`. + /// + /// ### Why is this bad? + /// It is good custom to have both methods, because for + /// some data structures, asking about the length will be a costly operation, + /// whereas `.is_empty()` can usually answer in constant time. Also it used to + /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that + /// lint will ignore such entities. + /// + /// ### Example + /// ```ignore + /// impl X { + /// pub fn len(&self) -> usize { + /// .. + /// } + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub LEN_WITHOUT_IS_EMPTY, + style, + "traits or impls with a public `len` method but no corresponding `is_empty` method" +} + +declare_lint_pass!(LenWithoutIsEmpty => [LEN_WITHOUT_IS_EMPTY]); + +impl<'tcx> LateLintPass<'tcx> for LenWithoutIsEmpty { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind + && !item.span.from_expansion() + { + check_trait_items(cx, item, ident, trait_items); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if item.ident.name == sym::len + && let ImplItemKind::Fn(sig, _) = &item.kind + && sig.decl.implicit_self.has_implicit_self() + && sig.decl.inputs.len() == 1 + && cx.effective_visibilities.is_exported(item.owner_id.def_id) + && matches!(sig.decl.output, FnRetTy::Return(_)) + && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) + && imp.of_trait.is_none() + && let TyKind::Path(ty_path) = &imp.self_ty.kind + && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() + && let Some(local_id) = ty_id.as_local() + && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id) + && let Some(output) = LenOutput::new(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) + { + let (name, kind) = match cx.tcx.hir_node(ty_hir_id) { + Node::ForeignItem(x) => (x.ident.name, "extern type"), + Node::Item(x) => match x.kind { + ItemKind::Struct(ident, ..) => (ident.name, "struct"), + ItemKind::Enum(ident, ..) => (ident.name, "enum"), + ItemKind::Union(ident, ..) => (ident.name, "union"), + _ => (x.kind.ident().unwrap().name, "type"), + }, + _ => return, + }; + check_for_is_empty( + cx, + sig.span, + sig.decl.implicit_self, + output, + ty_id, + name, + kind, + item.hir_id(), + ty_hir_id, + ); + } + } +} + +fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Ident, trait_items: &[TraitItemId]) { + fn is_named_self(cx: &LateContext<'_>, item: TraitItemId, name: Symbol) -> bool { + cx.tcx.item_name(item.owner_id) == name + && matches!( + cx.tcx.fn_arg_idents(item.owner_id), + [Some(Ident { + name: kw::SelfLower, + .. + })], + ) + } + + // fill the set with current and super traits + fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) { + if set.insert(traitt) { + for supertrait in supertrait_def_ids(cx.tcx, traitt) { + fill_trait_set(supertrait, set, cx); + } + } + } + + if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id) + && trait_items.iter().any(|&i| is_named_self(cx, i, sym::len)) + { + let mut current_and_super_traits = DefIdSet::default(); + fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); + let is_empty_method_found = current_and_super_traits + .items() + .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) + .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); + + if !is_empty_method_found { + span_lint( + cx, + LEN_WITHOUT_IS_EMPTY, + visited_trait.span, + format!( + "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method", + ident.name + ), + ); + } + } +} + +fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { + if let ty::Alias(_, alias_ty) = ty.kind() + && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id) + && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin + && let [GenericBound::Trait(trait_ref)] = &opaque.bounds + && let Some(segment) = trait_ref.trait_ref.path.segments.last() + && let Some(generic_args) = segment.args + && let [constraint] = generic_args.constraints + && let Some(ty) = constraint.ty() + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let [segment] = path.segments + { + return Some(segment); + } + + None +} + +fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool { + if let Some(generic_args) = segment.args + && let [GenericArg::Type(ty), ..] = &generic_args.args + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let [segment, ..] = &path.segments + && matches!(segment.res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) + { + true + } else { + false + } +} + +#[derive(Debug, Clone, Copy)] +enum LenOutput { + Integral, + Option(DefId), + Result(DefId), +} + +impl LenOutput { + fn new<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option { + if let Some(segment) = extract_future_output(cx, sig.output()) { + let res = segment.res; + + if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { + return Some(Self::Integral); + } + + if let Res::Def(_, def_id) = res + && let Some(res) = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::Option) => Some(Self::Option(def_id)), + Some(sym::Result) => Some(Self::Result(def_id)), + _ => None, + } + && is_first_generic_integral(segment) + { + return Some(res); + } + + return None; + } + + match *sig.output().kind() { + ty::Int(_) | ty::Uint(_) => Some(Self::Integral), + ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Option) => subs.type_at(0).is_integral().then(|| Self::Option(adt.did())), + Some(sym::Result) => subs.type_at(0).is_integral().then(|| Self::Result(adt.did())), + _ => None, + }, + _ => None, + } + } + + fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, is_empty_output: Ty<'tcx>) -> bool { + if let Some(segment) = extract_future_output(cx, is_empty_output) { + return match (self, segment.res) { + (_, Res::PrimTy(PrimTy::Bool)) => true, + (Self::Option(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Option, def_id) => true, + (Self::Result(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Result, def_id) => true, + _ => false, + }; + } + + match (self, is_empty_output.kind()) { + (_, &ty::Bool) => true, + (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), + (Self::Result(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), + _ => false, + } + } +} + +/// The expected signature of `is_empty`, based on that of `len` +fn expected_is_empty_sig(len_output: LenOutput, len_self_kind: ImplicitSelfKind) -> String { + let self_ref = match len_self_kind { + ImplicitSelfKind::RefImm => "&", + ImplicitSelfKind::RefMut => "&(mut) ", + _ => "", + }; + match len_output { + LenOutput::Integral => format!("expected signature: `({self_ref}self) -> bool`"), + LenOutput::Option(_) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") + }, + LenOutput::Result(..) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") + }, + } +} + +/// Checks if the given signature matches the expectations for `is_empty` +fn check_is_empty_sig<'tcx>( + cx: &LateContext<'tcx>, + is_empty_sig: FnSig<'tcx>, + len_self_kind: ImplicitSelfKind, + len_output: LenOutput, +) -> bool { + if let [is_empty_self_arg, is_empty_output] = &**is_empty_sig.inputs_and_output + && len_output.matches_is_empty_output(cx, *is_empty_output) + { + match (is_empty_self_arg.kind(), len_self_kind) { + // if `len` takes `&self`, `is_empty` should do so as well + (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) + // if `len` takes `&mut self`, `is_empty` may take that _or_ `&self` (#16190) + | (ty::Ref(_, _, Mutability::Mut | Mutability::Not), ImplicitSelfKind::RefMut) => true, + // if len takes `self`, `is_empty` should do so as well + // XXX: we might want to relax this to allow `&self` and `&mut self` + (_, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut) if !is_empty_self_arg.is_ref() => true, + _ => false, + } + } else { + false + } +} + +/// Checks if the given type has an `is_empty` method with the appropriate signature. +#[expect(clippy::too_many_arguments)] +fn check_for_is_empty( + cx: &LateContext<'_>, + len_span: Span, + len_self_kind: ImplicitSelfKind, + len_output: LenOutput, + impl_ty: DefId, + item_name: Symbol, + item_kind: &str, + len_method_hir_id: HirId, + ty_decl_hir_id: HirId, +) { + // Implementor may be a type alias, in which case we need to get the `DefId` of the aliased type to + // find the correct inherent impls. + let impl_ty = if let Some(adt) = cx.tcx.type_of(impl_ty).skip_binder().ty_adt_def() { + adt.did() + } else { + return; + }; + + let is_empty = cx + .tcx + .inherent_impls(impl_ty) + .iter() + .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty)) + .find(|item| item.is_fn()); + + let (msg, is_empty_span, is_empty_expected_sig) = match is_empty { + None => ( + format!("{item_kind} `{item_name}` has a public `len` method, but no `is_empty` method"), + None, + None, + ), + Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => ( + format!("{item_kind} `{item_name}` has a public `len` method, but a private `is_empty` method"), + Some(cx.tcx.def_span(is_empty.def_id)), + None, + ), + Some(is_empty) + if !(is_empty.is_method() + && check_is_empty_sig( + cx, + cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), + len_self_kind, + len_output, + )) => + { + ( + format!( + "{item_kind} `{item_name}` has a public `len` method, but the `is_empty` method has an unexpected signature", + ), + Some(cx.tcx.def_span(is_empty.def_id)), + Some(expected_is_empty_sig(len_output, len_self_kind)), + ) + }, + Some(_) => return, + }; + + if !fulfill_or_allowed(cx, LEN_WITHOUT_IS_EMPTY, [len_method_hir_id, ty_decl_hir_id]) { + span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, len_span, msg, |db| { + if let Some(span) = is_empty_span { + db.span_note(span, "`is_empty` defined here"); + } + if let Some(expected_sig) = is_empty_expected_sig { + db.note(expected_sig); + } + }); + } +} diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 877bd34a732bc..2e576da38b894 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -1,27 +1,20 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; -use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, parent_item_name, peel_ref_operators, sym}; +use clippy_utils::{parent_item_name, peel_ref_operators, sym}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::def::Res; -use rustc_hir::def_id::{DefId, DefIdSet}; -use rustc_hir::{ - BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind, ImplicitSelfKind, - Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy, QPath, RustcVersion, - StabilityLevel, StableSince, TraitItemId, TyKind, -}; +use rustc_hir::def_id::DefId; +use rustc_hir::{BinOpKind, Expr, ExprKind, PatExprKind, PatKind, RustcVersion, StabilityLevel, StableSince}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, FnSig, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::symbol::kw; -use rustc_span::{Ident, Span, Symbol}; -use rustc_trait_selection::traits::supertrait_def_ids; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -58,32 +51,6 @@ declare_clippy_lint! { "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead" } -declare_clippy_lint! { - /// ### What it does - /// Checks for items that implement `.len()` but not - /// `.is_empty()`. - /// - /// ### Why is this bad? - /// It is good custom to have both methods, because for - /// some data structures, asking about the length will be a costly operation, - /// whereas `.is_empty()` can usually answer in constant time. Also it used to - /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that - /// lint will ignore such entities. - /// - /// ### Example - /// ```ignore - /// impl X { - /// pub fn len(&self) -> usize { - /// .. - /// } - /// } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub LEN_WITHOUT_IS_EMPTY, - style, - "traits or impls with a public `len` method but no corresponding `is_empty` method" -} - declare_clippy_lint! { /// ### What it does /// Checks for comparing to an empty slice such as `""` or `[]`, @@ -126,7 +93,7 @@ pub struct LenZero { msrv: Msrv, } -impl_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]); +impl_lint_pass!(LenZero => [LEN_ZERO, COMPARISON_TO_EMPTY]); impl LenZero { pub fn new(conf: &'static Conf) -> Self { @@ -135,54 +102,6 @@ impl LenZero { } impl<'tcx> LateLintPass<'tcx> for LenZero { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind - && !item.span.from_expansion() - { - check_trait_items(cx, item, ident, trait_items); - } - } - - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if item.ident.name == sym::len - && let ImplItemKind::Fn(sig, _) = &item.kind - && sig.decl.implicit_self.has_implicit_self() - && sig.decl.inputs.len() == 1 - && cx.effective_visibilities.is_exported(item.owner_id.def_id) - && matches!(sig.decl.output, FnRetTy::Return(_)) - && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) - && imp.of_trait.is_none() - && let TyKind::Path(ty_path) = &imp.self_ty.kind - && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() - && let Some(local_id) = ty_id.as_local() - && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id) - && let Some(output) = - parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) - { - let (name, kind) = match cx.tcx.hir_node(ty_hir_id) { - Node::ForeignItem(x) => (x.ident.name, "extern type"), - Node::Item(x) => match x.kind { - ItemKind::Struct(ident, ..) => (ident.name, "struct"), - ItemKind::Enum(ident, ..) => (ident.name, "enum"), - ItemKind::Union(ident, ..) => (ident.name, "union"), - _ => (x.kind.ident().unwrap().name, "type"), - }, - _ => return, - }; - check_for_is_empty( - cx, - sig.span, - sig.decl.implicit_self, - output, - ty_id, - name, - kind, - item.hir_id(), - ty_hir_id, - ); - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Let(lt) = expr.kind && match lt.pat.kind { @@ -356,256 +275,6 @@ fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { } } -fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Ident, trait_items: &[TraitItemId]) { - fn is_named_self(cx: &LateContext<'_>, item: TraitItemId, name: Symbol) -> bool { - cx.tcx.item_name(item.owner_id) == name - && matches!( - cx.tcx.fn_arg_idents(item.owner_id), - [Some(Ident { - name: kw::SelfLower, - .. - })], - ) - } - - // fill the set with current and super traits - fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) { - if set.insert(traitt) { - for supertrait in supertrait_def_ids(cx.tcx, traitt) { - fill_trait_set(supertrait, set, cx); - } - } - } - - if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id) - && trait_items.iter().any(|&i| is_named_self(cx, i, sym::len)) - { - let mut current_and_super_traits = DefIdSet::default(); - fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); - let is_empty_method_found = current_and_super_traits - .items() - .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) - .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); - - if !is_empty_method_found { - span_lint( - cx, - LEN_WITHOUT_IS_EMPTY, - visited_trait.span, - format!( - "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method", - ident.name - ), - ); - } - } -} - -#[derive(Debug, Clone, Copy)] -enum LenOutput { - Integral, - Option(DefId), - Result(DefId), -} - -fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - if let ty::Alias(_, alias_ty) = ty.kind() - && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id) - && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin - && let [GenericBound::Trait(trait_ref)] = &opaque.bounds - && let Some(segment) = trait_ref.trait_ref.path.segments.last() - && let Some(generic_args) = segment.args - && let [constraint] = generic_args.constraints - && let Some(ty) = constraint.ty() - && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - && let [segment] = path.segments - { - return Some(segment); - } - - None -} - -fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool { - if let Some(generic_args) = segment.args - && let [GenericArg::Type(ty), ..] = &generic_args.args - && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - && let [segment, ..] = &path.segments - && matches!(segment.res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) - { - true - } else { - false - } -} - -fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option { - if let Some(segment) = extract_future_output(cx, sig.output()) { - let res = segment.res; - - if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { - return Some(LenOutput::Integral); - } - - if let Res::Def(_, def_id) = res - && let Some(res) = match cx.tcx.get_diagnostic_name(def_id) { - Some(sym::Option) => Some(LenOutput::Option(def_id)), - Some(sym::Result) => Some(LenOutput::Result(def_id)), - _ => None, - } - && is_first_generic_integral(segment) - { - return Some(res); - } - - return None; - } - - match *sig.output().kind() { - ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral), - ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) { - Some(sym::Option) => subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did())), - Some(sym::Result) => subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did())), - _ => None, - }, - _ => None, - } -} - -impl LenOutput { - fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if let Some(segment) = extract_future_output(cx, ty) { - return match (self, segment.res) { - (_, Res::PrimTy(PrimTy::Bool)) => true, - (Self::Option(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Option, def_id) => true, - (Self::Result(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Result, def_id) => true, - _ => false, - }; - } - - match (self, ty.kind()) { - (_, &ty::Bool) => true, - (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), - (Self::Result(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), - _ => false, - } - } - - fn expected_sig(self, self_kind: ImplicitSelfKind) -> String { - let self_ref = match self_kind { - ImplicitSelfKind::RefImm => "&", - ImplicitSelfKind::RefMut => "&mut ", - _ => "", - }; - match self { - Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"), - Self::Option(_) => { - format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") - }, - Self::Result(..) => { - format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") - }, - } - } -} - -/// Checks if the given signature matches the expectations for `is_empty` -fn check_is_empty_sig<'tcx>( - cx: &LateContext<'tcx>, - sig: FnSig<'tcx>, - self_kind: ImplicitSelfKind, - len_output: LenOutput, -) -> bool { - match &**sig.inputs_and_output { - [arg, res] if len_output.matches_is_empty_output(cx, *res) => { - matches!( - (arg.kind(), self_kind), - (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) - | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut) - ) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut)) - }, - _ => false, - } -} - -/// Checks if the given type has an `is_empty` method with the appropriate signature. -#[expect(clippy::too_many_arguments)] -fn check_for_is_empty( - cx: &LateContext<'_>, - span: Span, - self_kind: ImplicitSelfKind, - output: LenOutput, - impl_ty: DefId, - item_name: Symbol, - item_kind: &str, - len_method_hir_id: HirId, - ty_decl_hir_id: HirId, -) { - // Implementor may be a type alias, in which case we need to get the `DefId` of the aliased type to - // find the correct inherent impls. - let impl_ty = if let Some(adt) = cx.tcx.type_of(impl_ty).skip_binder().ty_adt_def() { - adt.did() - } else { - return; - }; - - let is_empty = cx - .tcx - .inherent_impls(impl_ty) - .iter() - .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty)) - .find(|item| item.is_fn()); - - let (msg, is_empty_span, self_kind) = match is_empty { - None => ( - format!( - "{item_kind} `{}` has a public `len` method, but no `is_empty` method", - item_name.as_str(), - ), - None, - None, - ), - Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => ( - format!( - "{item_kind} `{}` has a public `len` method, but a private `is_empty` method", - item_name.as_str(), - ), - Some(cx.tcx.def_span(is_empty.def_id)), - None, - ), - Some(is_empty) - if !(is_empty.is_method() - && check_is_empty_sig( - cx, - cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), - self_kind, - output, - )) => - { - ( - format!( - "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature", - item_name.as_str(), - ), - Some(cx.tcx.def_span(is_empty.def_id)), - Some(self_kind), - ) - }, - Some(_) => return, - }; - - if !fulfill_or_allowed(cx, LEN_WITHOUT_IS_EMPTY, [len_method_hir_id, ty_decl_hir_id]) { - span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| { - if let Some(span) = is_empty_span { - db.span_note(span, "`is_empty` defined here"); - } - if let Some(self_kind) = self_kind { - db.note(output.expected_sig(self_kind)); - } - }); - } -} - fn is_empty_string(expr: &Expr<'_>) -> bool { if let ExprKind::Lit(lit) = expr.kind && let LitKind::Str(lit, _) = lit.node diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index bc62d9b8450c7..40487fe48f222 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -182,6 +182,7 @@ mod large_include_file; mod large_stack_arrays; mod large_stack_frames; mod legacy_numeric_constants; +mod len_without_is_empty; mod len_zero; mod let_if_seq; mod let_underscore; @@ -201,6 +202,7 @@ mod manual_clamp; mod manual_float_methods; mod manual_hash_one; mod manual_ignore_case_cmp; +mod manual_ilog2; mod manual_is_ascii_check; mod manual_is_power_of_two; mod manual_let_else; @@ -538,6 +540,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(unnecessary_mut_passed::UnnecessaryMutPassed)), Box::new(|_| Box::>::default()), Box::new(move |_| Box::new(len_zero::LenZero::new(conf))), + Box::new(|_| Box::new(len_without_is_empty::LenWithoutIsEmpty)), Box::new(move |_| Box::new(attrs::Attributes::new(conf))), Box::new(|_| Box::new(blocks_in_conditions::BlocksInConditions)), Box::new(|_| Box::new(unicode::Unicode)), @@ -848,6 +851,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(toplevel_ref_arg::ToplevelRefArg)), Box::new(|_| Box::new(volatile_composites::VolatileComposites)), Box::new(|_| Box::::default()), + Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index 2545f81f1afad..6c95c7b54c500 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -43,26 +43,26 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { }; // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be - // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used + // passed by reference. TODO: If the struct can be partially moved from and the struct isn't used // afterwards a mutable borrow of a field isn't necessary. - let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut) + let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); + let iterator_by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut) || !iter_expr_struct.can_move || !iter_expr_struct.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr_struct, expr) { - ".by_ref()" + make_iterator_snippet(cx, iter_expr, &iterator) } else { - "" + iterator.into_owned() }; - let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); span_lint_and_sugg( cx, WHILE_LET_ON_ITERATOR, expr.span.with_hi(let_expr.span.hi()), "this loop could be written as a `for` loop", "try", - format!("{loop_label}for {loop_var} in {iterator}{by_ref}"), + format!("{loop_label}for {loop_var} in {iterator_by_ref}"), applicability, ); } @@ -355,3 +355,22 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & .is_break() } } + +/// Constructs the transformed iterator expression for the suggestion. +/// Returns `iterator.by_ref()` unless the last deref adjustment targets an unsized type, +/// in which case it applies all derefs (e.g., `&mut **iterator` or `&mut ***iterator`). +fn make_iterator_snippet<'tcx>(cx: &LateContext<'tcx>, iter_expr: &Expr<'tcx>, iterator: &str) -> String { + if let Some((n, adjust)) = cx + .typeck_results() + .expr_adjustments(iter_expr) + .iter() + .take_while(|x| matches!(x.kind, Adjust::Deref(_))) + .enumerate() + .last() + && !adjust.target.is_sized(cx.tcx, cx.typing_env()) + { + format!("&mut {:* Self { + Self { msrv: conf.msrv } + } +} + +impl_lint_pass!(ManualIlog2 => [MANUAL_ILOG2]); + +impl LateLintPass<'_> for ManualIlog2 { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if expr.span.in_external_macro(cx.sess().source_map()) { + return; + } + + match expr.kind { + // `BIT_WIDTH - 1 - n.leading_zeros()` + ExprKind::Binary(op, left, right) + if left.span.eq_ctxt(right.span) + && op.node == BinOpKind::Sub + && let ExprKind::Lit(lit) = left.kind + && let LitKind::Int(Pu128(val), _) = lit.node + && let ExprKind::MethodCall(leading_zeros, recv, [], _) = right.kind + && leading_zeros.ident.name == sym::leading_zeros + && let ty = cx.typeck_results().expr_ty(recv) + && let Some(bit_width) = match ty.kind() { + ty::Uint(uint_ty) => uint_ty.bit_width(), + ty::Int(_) => { + // On non-positive integers, `ilog2` would panic, which might be a sign that the author does + // in fact want to calculate something different, so stay on the safer side and don't + // suggest anything. + return; + }, + _ => return, + } + && val == u128::from(bit_width) - 1 + && self.msrv.meets(cx, msrvs::ILOG2) + && !is_from_proc_macro(cx, expr) => + { + emit(cx, recv, expr); + }, + + // `n.ilog(2)` + ExprKind::MethodCall(ilog, recv, [two], _) + if expr.span.eq_ctxt(two.span) + && ilog.ident.name == sym::ilog + && let ExprKind::Lit(lit) = two.kind + && let LitKind::Int(Pu128(2), _) = lit.node + && cx.typeck_results().expr_ty_adjusted(recv).is_integral() + /* no need to check MSRV here, as `ilog` and `ilog2` were introduced simultaneously */ + && !is_from_proc_macro(cx, expr) => + { + emit(cx, recv, expr); + }, + + _ => {}, + } + } +} + +fn emit(cx: &LateContext<'_>, recv: &Expr<'_>, full_expr: &Expr<'_>) { + let mut app = Applicability::MachineApplicable; + let recv = snippet_with_applicability(cx, recv.span, "_", &mut app); + span_lint_and_sugg( + cx, + MANUAL_ILOG2, + full_expr.span, + "manually reimplementing `ilog2`", + "try", + format!("{recv}.ilog2()"), + app, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index b5f631e8fea33..89411115f730d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -1,7 +1,8 @@ //! Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!` use super::REDUNDANT_PATTERN_MATCHING; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher::has_let_expr; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use rustc_ast::LitKind; @@ -43,18 +44,23 @@ pub(crate) fn check_if_let<'tcx>( { ex_new = ex_inner; } - span_lint_and_sugg( + span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, expr.span, - "if let .. else expression looks like `matches!` macro", - "try", - format!( - "{}matches!({}, {pat})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), - applicability, + "`if let .. else` expression looks like `matches!` macro", + |diag| { + diag.span_suggestion_verbose( + expr.span, + "use `matches!` directly", + format!( + "{}matches!({}, {pat})", + if b0 { "" } else { "!" }, + snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), + ), + applicability, + ); + }, ); } } @@ -87,7 +93,10 @@ pub(super) fn check_match<'tcx>( // ```rs // matches!(e, Either::Left $(if $guard)|+) // ``` - middle_arms.is_empty() + // + // But if the guard _is_ present, it may not be an `if-let` guard, as `matches!` doesn't + // support these (currently?) + (middle_arms.is_empty() && first_arm.guard.is_none_or(|g| !has_let_expr(g))) // - (added in #6216) There are middle arms // @@ -169,18 +178,23 @@ pub(super) fn check_match<'tcx>( { ex_new = ex_inner; } - span_lint_and_sugg( + span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, e.span, "match expression looks like `matches!` macro", - "try", - format!( - "{}matches!({}, {pat_and_guard})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), - applicability, + |diag| { + diag.span_suggestion_verbose( + e.span, + "use `matches!` directly", + format!( + "{}matches!({}, {pat_and_guard})", + if b0 { "" } else { "!" }, + snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), + ), + applicability, + ); + }, ); true } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 2196ce92b0ab5..a3dd967bd77a9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -4,18 +4,20 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::sym; use rustc_ast::ast; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::def::Res; +use rustc_hir::{self as hir, Expr}; use rustc_lint::LateContext; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; +use rustc_span::Symbol; -pub fn check( +pub fn check_unwrap_or( cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - arith_lhs: &hir::Expr<'_>, - arith_rhs: &hir::Expr<'_>, - unwrap_arg: &hir::Expr<'_>, - arith: &str, + expr: &Expr<'_>, + arith_lhs: &Expr<'_>, + arith_rhs: &Expr<'_>, + unwrap_arg: &Expr<'_>, + arith: Symbol, ) { let ty = cx.typeck_results().expr_ty(arith_lhs); if !ty.is_integral() { @@ -26,35 +28,75 @@ pub fn check( return; }; - if ty.is_signed() { - use self::MinMax::{Max, Min}; - use self::Sign::{Neg, Pos}; + let Some(checked_arith) = CheckedArith::new(arith) else { + return; + }; + + check(cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith); +} + +pub(super) fn check_sub_unwrap_or_default( + cx: &LateContext<'_>, + expr: &Expr<'_>, + arith_lhs: &Expr<'_>, + arith_rhs: &Expr<'_>, +) { + let ty = cx.typeck_results().expr_ty(arith_lhs); + if !ty.is_integral() { + return; + } + + let mm = if ty.is_signed() { + return; // iN::default() is 0, which is neither MIN nor MAX + } else { + MinMax::Min // uN::default() is 0, which is also the MIN + }; + + let checked_arith = CheckedArith::Sub; + check(cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith); +} + +fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + arith_lhs: &Expr<'_>, + arith_rhs: &Expr<'_>, + ty: Ty<'_>, + mm: MinMax, + checked_arith: CheckedArith, +) { + use self::MinMax::{Max, Min}; + use self::Sign::{Neg, Pos}; + use CheckedArith::{Add, Mul, Sub}; + + if ty.is_signed() { let Some(sign) = lit_sign(arith_rhs) else { return; }; - match (arith, sign, mm) { - ("add", Pos, Max) | ("add", Neg, Min) | ("sub", Neg, Max) | ("sub", Pos, Min) => (), + match (checked_arith, sign, mm) { + (Add, Pos, Max) | (Add, Neg, Min) | (Sub, Neg, Max) | (Sub, Pos, Min) => (), // "mul" is omitted because lhs can be negative. _ => return, } } else { - match (mm, arith) { - (MinMax::Max, "add" | "mul") | (MinMax::Min, "sub") => (), + match (mm, checked_arith) { + (Max, Add | Mul) | (Min, Sub) => (), _ => return, } } let mut applicability = Applicability::MachineApplicable; + let saturating_arith = checked_arith.as_saturating(); span_lint_and_sugg( cx, super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - format!("consider using `saturating_{arith}`"), + format!("consider using `{saturating_arith}`"), format!( - "{}.saturating_{arith}({})", + "{}.{saturating_arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), ), @@ -62,13 +104,40 @@ pub fn check( ); } +#[derive(Clone, Copy)] +enum CheckedArith { + Add, + Sub, + Mul, +} + +impl CheckedArith { + fn new(sym: Symbol) -> Option { + let res = match sym { + sym::checked_add => Self::Add, + sym::checked_sub => Self::Sub, + sym::checked_mul => Self::Mul, + _ => return None, + }; + Some(res) + } + + fn as_saturating(self) -> &'static str { + match self { + Self::Add => "saturating_add", + Self::Sub => "saturating_sub", + Self::Mul => "saturating_mul", + } + } +} + #[derive(PartialEq, Eq)] enum MinMax { Min, Max, } -fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { +fn is_min_or_max(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { // `T::max_value()` `T::min_value()` inherent methods if let hir::ExprKind::Call(func, []) = &expr.kind && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind @@ -106,7 +175,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { (0, if bits == 128 { !0 } else { (1 << bits) - 1 }) }; - let check_lit = |expr: &hir::Expr<'_>, check_min: bool| { + let check_lit = |expr: &Expr<'_>, check_min: bool| { if let hir::ExprKind::Lit(lit) = &expr.kind && let ast::LitKind::Int(value, _) = lit.node { @@ -141,7 +210,7 @@ enum Sign { Neg, } -fn lit_sign(expr: &hir::Expr<'_>) -> Option { +fn lit_sign(expr: &Expr<'_>) -> Option { if let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = &expr.kind { if let hir::ExprKind::Lit(..) = &inner.kind { return Some(Sign::Neg); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index c22b0a548e3df..248a147cfd77c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -94,6 +94,7 @@ mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; mod path_ends_with_ext; +mod ptr_offset_by_literal; mod ptr_offset_with_cast; mod range_zip_with_len; mod read_line_without_trim; @@ -888,7 +889,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub SEARCH_IS_SOME, - complexity, + nursery, "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)" } @@ -1728,6 +1729,40 @@ declare_clippy_lint! { "Check for offset calculations on raw pointers to zero-sized types" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of the `offset` pointer method with an integer + /// literal. + /// + /// ### Why is this bad? + /// The `add` and `sub` methods more accurately express the intent. + /// + /// ### Example + /// ```no_run + /// let vec = vec![b'a', b'b', b'c']; + /// let ptr = vec.as_ptr(); + /// + /// unsafe { + /// ptr.offset(-8); + /// } + /// ``` + /// + /// Could be written: + /// + /// ```no_run + /// let vec = vec![b'a', b'b', b'c']; + /// let ptr = vec.as_ptr(); + /// + /// unsafe { + /// ptr.sub(8); + /// } + /// ``` + #[clippy::version = "1.92.0"] + pub PTR_OFFSET_BY_LITERAL, + pedantic, + "unneeded pointer offset" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of the `offset` pointer method with a `usize` casted to an @@ -4635,7 +4670,7 @@ declare_clippy_lint! { /// let x = vec![String::new()]; /// let _ = x.iter().map(|x| x.len()); /// ``` - #[clippy::version = "1.90.0"] + #[clippy::version = "1.92.0"] pub REDUNDANT_ITER_CLONED, perf, "detects redundant calls to `Iterator::cloned`" @@ -4659,7 +4694,7 @@ declare_clippy_lint! { /// let x: Option = Some(4); /// let y = x.unwrap_or_else(|| 2 * k); /// ``` - #[clippy::version = "1.88.0"] + #[clippy::version = "1.92.0"] pub UNNECESSARY_OPTION_MAP_OR_ELSE, suspicious, "making no use of the \"map closure\" when calling `.map_or_else(|| 2 * k, |n| n)`" @@ -4803,6 +4838,7 @@ impl_lint_pass!(Methods => [ UNINIT_ASSUMED_INIT, MANUAL_SATURATING_ARITHMETIC, ZST_OFFSET, + PTR_OFFSET_BY_LITERAL, PTR_OFFSET_WITH_CAST, FILETYPE_IS_FILE, OPTION_AS_REF_DEREF, @@ -5426,6 +5462,7 @@ impl Methods { zst_offset::check(cx, expr, recv); ptr_offset_with_cast::check(cx, name, expr, recv, arg, self.msrv); + ptr_offset_by_literal::check(cx, expr, self.msrv); }, (sym::ok_or_else, [arg]) => { unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"); @@ -5567,14 +5604,7 @@ impl Methods { (sym::unwrap_or, [u_arg]) => { match method_call(recv) { Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => { - manual_saturating_arithmetic::check( - cx, - expr, - lhs, - rhs, - u_arg, - &arith.as_str()[const { "checked_".len() }..], - ); + manual_saturating_arithmetic::check_unwrap_or(cx, expr, lhs, rhs, u_arg, arith); }, Some((sym::map, m_recv, [m_arg], span, _)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); @@ -5595,6 +5625,9 @@ impl Methods { }, (sym::unwrap_or_default, []) => { match method_call(recv) { + Some((sym::checked_sub, lhs, [rhs], _, _)) => { + manual_saturating_arithmetic::check_sub_unwrap_or_default(cx, expr, lhs, rhs); + }, Some((sym::map, m_recv, [arg], span, _)) => { manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); }, diff --git a/src/tools/clippy/clippy_lints/src/methods/ptr_offset_by_literal.rs b/src/tools/clippy/clippy_lints/src/methods/ptr_offset_by_literal.rs new file mode 100644 index 0000000000000..b5d2add65cf19 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/ptr_offset_by_literal.rs @@ -0,0 +1,138 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::sym; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Lit, UnOp}; +use rustc_lint::LateContext; +use std::cmp::Ordering; +use std::fmt; + +use super::PTR_OFFSET_BY_LITERAL; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Msrv) { + // `pointer::add` and `pointer::wrapping_add` are only stable since 1.26.0. These functions + // became const-stable in 1.61.0, the same version that `pointer::offset` became const-stable. + if !msrv.meets(cx, msrvs::POINTER_ADD_SUB_METHODS) { + return; + } + + let ExprKind::MethodCall(method_name, recv, [arg_expr], _) = expr.kind else { + return; + }; + + let method = match method_name.ident.name { + sym::offset => Method::Offset, + sym::wrapping_offset => Method::WrappingOffset, + _ => return, + }; + + if !cx.typeck_results().expr_ty_adjusted(recv).is_raw_ptr() { + return; + } + + // Check if the argument to the method call is a (negated) literal. + let Some((literal, literal_text)) = expr_as_literal(cx, arg_expr) else { + return; + }; + + match method.suggestion(literal) { + None => { + let msg = format!("use of `{method}` with zero"); + span_lint_and_then(cx, PTR_OFFSET_BY_LITERAL, expr.span, msg, |diag| { + diag.span_suggestion( + expr.span.with_lo(recv.span.hi()), + format!("remove the call to `{method}`"), + String::new(), + Applicability::MachineApplicable, + ); + }); + }, + Some(method_suggestion) => { + let msg = format!("use of `{method}` with a literal"); + span_lint_and_then(cx, PTR_OFFSET_BY_LITERAL, expr.span, msg, |diag| { + diag.multipart_suggestion( + format!("use `{method_suggestion}` instead"), + vec![ + (method_name.ident.span, method_suggestion.to_string()), + (arg_expr.span, literal_text), + ], + Applicability::MachineApplicable, + ); + }); + }, + } +} + +fn get_literal_bits<'tcx>(expr: &'tcx Expr<'tcx>) -> Option { + match expr.kind { + ExprKind::Lit(Lit { + node: LitKind::Int(packed_u128, _), + .. + }) => Some(packed_u128.get()), + _ => None, + } +} + +// If the given expression is a (negated) literal, return its value. +fn expr_as_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<(i128, String)> { + if let Some(literal_bits) = get_literal_bits(expr) { + // The value must fit in a isize, so we can't have overflow here. + return Some((literal_bits.cast_signed(), format_isize_literal(cx, expr)?)); + } + + if let ExprKind::Unary(UnOp::Neg, inner) = expr.kind + && let Some(literal_bits) = get_literal_bits(inner) + { + return Some((-(literal_bits.cast_signed()), format_isize_literal(cx, inner)?)); + } + + None +} + +fn format_isize_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { + let text = expr.span.get_source_text(cx)?; + let text = peel_parens_str(&text); + Some(text.trim_end_matches("isize").trim_end_matches('_').to_string()) +} + +fn peel_parens_str(snippet: &str) -> &str { + let mut s = snippet.trim(); + while let Some(next) = s.strip_prefix("(").and_then(|suf| suf.strip_suffix(")")) { + s = next.trim(); + } + s +} + +#[derive(Copy, Clone)] +enum Method { + Offset, + WrappingOffset, +} + +impl Method { + fn suggestion(self, literal: i128) -> Option<&'static str> { + match Ord::cmp(&literal, &0) { + Ordering::Greater => match self { + Method::Offset => Some("add"), + Method::WrappingOffset => Some("wrapping_add"), + }, + // `ptr.offset(0)` is equivalent to `ptr`, so no adjustment is needed + Ordering::Equal => None, + Ordering::Less => match self { + Method::Offset => Some("sub"), + Method::WrappingOffset => Some("wrapping_sub"), + }, + } + } +} + +impl fmt::Display for Method { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Offset => write!(f, "offset"), + Self::WrappingOffset => write!(f, "wrapping_offset"), + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 808adb7e71cee..87ee164a1760e 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -5,7 +5,7 @@ use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::{If, Range}; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace, root_macro_call}; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, hash_expr}; use rustc_ast::{BinOpKind, LitKind, RangeLimits}; @@ -67,16 +67,13 @@ declare_clippy_lint! { } declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); -fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: &[Span], f: F) +fn report_lint(cx: &LateContext<'_>, index_spans: Vec, msg: &'static str, f: F) where F: FnOnce(&mut Diag<'_, ()>), { - span_lint_and_then(cx, MISSING_ASSERTS_FOR_INDEXING, full_span, msg, |diag| { + span_lint_and_then(cx, MISSING_ASSERTS_FOR_INDEXING, index_spans, msg, |diag| { f(diag); - for span in indexes { - diag.span_note(*span, "slice indexed here"); - } - diag.note("asserting the length before indexing will elide bounds checks"); + diag.note_once("asserting the length before indexing will elide bounds checks"); }); } @@ -213,15 +210,6 @@ impl<'hir> IndexEntry<'hir> { | IndexEntry::IndexWithoutAssert { slice, .. } => slice, } } - - pub fn index_spans(&self) -> Option<&[Span]> { - match self { - IndexEntry::StrayAssert { .. } => None, - IndexEntry::AssertWithIndex { indexes, .. } | IndexEntry::IndexWithoutAssert { indexes, .. } => { - Some(indexes) - }, - } - } } /// Extracts the upper index of a slice indexing expression. @@ -354,63 +342,47 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un /// Inspects indexes and reports lints. /// /// Called at the end of this lint after all indexing and `assert!` expressions have been collected. -fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap>>) { - for bucket in map.values() { +fn report_indexes(cx: &LateContext<'_>, map: UnindexMap>>) { + for bucket in map.into_values() { for entry in bucket { - let Some(full_span) = entry - .index_spans() - .and_then(|spans| spans.first().zip(spans.last())) - .map(|(low, &high)| low.to(high)) - else { - continue; - }; - - match *entry { + match entry { IndexEntry::AssertWithIndex { highest_index, is_first_highest, asserted_len, - ref indexes, + indexes, comparison, assert_span, slice, macro_call, } if indexes.len() > 1 && !is_first_highest => { + let mut app = Applicability::MachineApplicable; + let slice_str = snippet_with_applicability(cx, slice.span, "_", &mut app); // if we have found an `assert!`, let's also check that it's actually right // and if it covers the highest index and if not, suggest the correct length let sugg = match comparison { // `v.len() < 5` and `v.len() <= 5` does nothing in terms of bounds checks. // The user probably meant `v.len() > 5` - LengthComparison::LengthLessThanInt | LengthComparison::LengthLessThanOrEqualInt => Some( - format!("assert!({}.len() > {highest_index})", snippet(cx, slice.span, "..")), - ), + LengthComparison::LengthLessThanInt | LengthComparison::LengthLessThanOrEqualInt => { + Some(format!("assert!({slice_str}.len() > {highest_index})",)) + }, // `5 < v.len()` == `v.len() > 5` - LengthComparison::IntLessThanLength if asserted_len < highest_index => Some(format!( - "assert!({}.len() > {highest_index})", - snippet(cx, slice.span, "..") - )), + LengthComparison::IntLessThanLength if asserted_len < highest_index => { + Some(format!("assert!({slice_str}.len() > {highest_index})",)) + }, // `5 <= v.len() == `v.len() >= 5` - LengthComparison::IntLessThanOrEqualLength if asserted_len <= highest_index => Some(format!( - "assert!({}.len() > {highest_index})", - snippet(cx, slice.span, "..") - )), + LengthComparison::IntLessThanOrEqualLength if asserted_len <= highest_index => { + Some(format!("assert!({slice_str}.len() > {highest_index})",)) + }, // `highest_index` here is rather a length, so we need to add 1 to it LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => match macro_call { - sym::assert_eq_macro => Some(format!( - "assert_eq!({}.len(), {})", - snippet(cx, slice.span, ".."), - highest_index + 1 - )), - sym::debug_assert_eq_macro => Some(format!( - "debug_assert_eq!({}.len(), {})", - snippet(cx, slice.span, ".."), - highest_index + 1 - )), - _ => Some(format!( - "assert!({}.len() == {})", - snippet(cx, slice.span, ".."), - highest_index + 1 - )), + sym::assert_eq_macro => { + Some(format!("assert_eq!({slice_str}.len(), {})", highest_index + 1)) + }, + sym::debug_assert_eq_macro => { + Some(format!("debug_assert_eq!({slice_str}.len(), {})", highest_index + 1)) + }, + _ => Some(format!("assert!({slice_str}.len() == {})", highest_index + 1)), }, _ => None, }; @@ -418,22 +390,21 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap if let Some(sugg) = sugg { report_lint( cx, - full_span, - "indexing into a slice multiple times with an `assert` that does not cover the highest index", indexes, + "indexing into a slice multiple times with an `assert` that does not cover the highest index", |diag| { - diag.span_suggestion( + diag.span_suggestion_verbose( assert_span, "provide the highest index that is indexed with", sugg, - Applicability::MachineApplicable, + app, ); }, ); } }, IndexEntry::IndexWithoutAssert { - ref indexes, + indexes, highest_index, is_first_highest, slice, @@ -442,9 +413,8 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap // adding an `assert!` that covers the highest index report_lint( cx, - full_span, - "indexing into a slice multiple times without an `assert`", indexes, + "indexing into a slice multiple times without an `assert`", |diag| { diag.help(format!( "consider asserting the length before indexing: `assert!({}.len() > {highest_index});`", @@ -469,6 +439,6 @@ impl LateLintPass<'_> for MissingAssertsForIndexing { ControlFlow::::Continue(()) }); - report_indexes(cx, &map); + report_indexes(cx, map); } } diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index 3a8a4dd0c7137..8970970f4b475 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -115,35 +115,41 @@ impl EarlyLintPass for MacroBraces { } fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBraces) -> Option { - let unnested_or_local = || { - !span.ctxt().outer_expn_data().call_site.from_expansion() + let unnested_or_local = |span: Span| { + !span.from_expansion() || span .macro_backtrace() .last() .is_some_and(|e| e.macro_def_id.is_some_and(DefId::is_local)) }; - let callsite_span = span.ctxt().outer_expn_data().call_site; - if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind + + let mut ctxt = span.ctxt(); + while !ctxt.is_root() { + let expn_data = ctxt.outer_expn_data(); + if let ExpnKind::Macro(MacroKind::Bang, mac_name) = expn_data.kind && let name = mac_name.as_str() && let Some(&braces) = mac_braces.macro_braces.get(name) - && let Some(snip) = callsite_span.get_source_text(cx) + && let Some(snip) = expn_data.call_site.get_source_text(cx) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 && let Some(macro_args_str) = snip.strip_prefix(name).and_then(|snip| snip.strip_prefix('!')) && let Some(old_open_brace @ ('{' | '(' | '[')) = macro_args_str.trim_start().chars().next() && old_open_brace != braces.0 - && unnested_or_local() - && !mac_braces.done.contains(&callsite_span) - { - Some(MacroInfo { - callsite_span, - callsite_snippet: snip, - old_open_brace, - braces, - }) - } else { - None + && unnested_or_local(expn_data.call_site) + && !mac_braces.done.contains(&expn_data.call_site) + { + return Some(MacroInfo { + callsite_span: expn_data.call_site, + callsite_snippet: snip, + old_open_brace, + braces, + }); + } + + ctxt = expn_data.call_site.ctxt(); } + + None } fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), span: Span, add_semi: bool) { diff --git a/src/tools/clippy/clippy_lints/src/operators/decimal_bitwise_operands.rs b/src/tools/clippy/clippy_lints/src/operators/decimal_bitwise_operands.rs new file mode 100644 index 0000000000000..8511f2151342d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/decimal_bitwise_operands.rs @@ -0,0 +1,76 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::numeric_literal; +use clippy_utils::numeric_literal::NumericLiteral; +use clippy_utils::source::SpanRangeExt; +use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::DECIMAL_BITWISE_OPERANDS; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, op: BinOpKind, left: &'tcx Expr<'_>, right: &'tcx Expr<'_>) { + if !matches!(op, BinOpKind::BitAnd | BinOpKind::BitOr | BinOpKind::BitXor) { + return; + } + + for expr in [left, right] { + check_expr(cx, expr); + } +} + +fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { + match &expr.kind { + ExprKind::Block(block, _) => { + if let Some(block_expr) = block.expr { + check_expr(cx, block_expr); + } + }, + ExprKind::Cast(cast_expr, _) => { + check_expr(cx, cast_expr); + }, + ExprKind::Unary(_, unary_expr) => { + check_expr(cx, unary_expr); + }, + ExprKind::AddrOf(_, _, addr_of_expr) => { + check_expr(cx, addr_of_expr); + }, + ExprKind::Lit(lit) => { + if let LitKind::Int(Pu128(val), _) = lit.node + && !is_single_digit(val) + && !is_power_of_twoish(val) + && let Some(src) = lit.span.get_source_text(cx) + && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) + && num_lit.is_decimal() + { + emit_lint(cx, lit.span, num_lit.suffix, val); + } + }, + _ => (), + } +} + +fn is_power_of_twoish(val: u128) -> bool { + val.is_power_of_two() || val.wrapping_add(1).is_power_of_two() +} + +fn is_single_digit(val: u128) -> bool { + val <= 9 +} + +fn emit_lint(cx: &LateContext<'_>, span: Span, suffix: Option<&str>, val: u128) { + span_lint_and_help( + cx, + DECIMAL_BITWISE_OPERANDS, + span, + "using decimal literal for bitwise operation", + None, + format!( + "use binary ({}), hex ({}), or octal ({}) notation for better readability", + numeric_literal::format(&format!("{val:#b}"), suffix, false), + numeric_literal::format(&format!("{val:#x}"), suffix, false), + numeric_literal::format(&format!("{val:#o}"), suffix, false), + ), + ); +} diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 8db2cc1d3f578..53b8e9e5d5ae7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -3,6 +3,7 @@ mod assign_op_pattern; mod bit_mask; mod cmp_owned; mod const_comparisons; +mod decimal_bitwise_operands; mod double_comparison; mod duration_subsec; mod eq_op; @@ -935,6 +936,28 @@ declare_clippy_lint! { "use of disallowed default division and remainder operations" } +declare_clippy_lint! { + /// ### What it does + /// Checks for decimal literals used as bit masks in bitwise operations. + /// + /// ### Why is this bad? + /// Using decimal literals for bit masks can make the code less readable and obscure the intended bit pattern. + /// Binary, hexadecimal, or octal literals make the bit pattern more explicit and easier to understand at a glance. + /// + /// ### Example + /// ```rust,no_run + /// let a = 14 & 6; // Bit pattern is not immediately clear + /// ``` + /// Use instead: + /// ```rust,no_run + /// let a = 0b1110 & 0b0110; + /// ``` + #[clippy::version = "1.93.0"] + pub DECIMAL_BITWISE_OPERANDS, + pedantic, + "use binary, hex, or octal literals for bitwise operations" +} + pub struct Operators { arithmetic_context: numeric_arithmetic::Context, verbose_bit_mask_threshold: u64, @@ -984,6 +1007,7 @@ impl_lint_pass!(Operators => [ MANUAL_IS_MULTIPLE_OF, MANUAL_DIV_CEIL, INVALID_UPCAST_COMPARISONS, + DECIMAL_BITWISE_OPERANDS ]); impl<'tcx> LateLintPass<'tcx> for Operators { @@ -1003,6 +1027,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators { needless_bitwise_bool::check(cx, e, op.node, lhs, rhs); manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv); manual_is_multiple_of::check(cx, e, op.node, lhs, rhs, self.msrv); + decimal_bitwise_operands::check(cx, op.node, lhs, rhs); } self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs); bit_mask::check(cx, e, op.node, lhs, rhs); @@ -1028,6 +1053,9 @@ impl<'tcx> LateLintPass<'tcx> for Operators { }, ExprKind::AssignOp(op, lhs, rhs) => { let bin_op = op.node.into(); + if !e.span.from_expansion() { + decimal_bitwise_operands::check(cx, bin_op, lhs, rhs); + } self.arithmetic_context.check_binary(cx, e, bin_op, lhs, rhs); misrefactored_assign_op::check(cx, e, bin_op, lhs, rhs); modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false); diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index d643f7aea497f..435cd7bcba4e3 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -18,8 +18,11 @@ mod wrong_transmute; use clippy_config::Conf; use clippy_utils::is_in_const_context; use clippy_utils::msrvs::Msrv; +use clippy_utils::sugg::Sugg; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; @@ -490,6 +493,32 @@ impl Transmute { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv } } + + /// When transmuting, a struct containing a single field works like the field. + /// This function extracts the field type and the expression to get the field. + fn extract_struct_field<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + outer_type: Ty<'tcx>, + outer: &'tcx Expr<'tcx>, + ) -> (Ty<'tcx>, Sugg<'tcx>) { + let mut applicability = Applicability::MachineApplicable; + let outer_sugg = Sugg::hir_with_context(cx, outer, e.span.ctxt(), "..", &mut applicability); + if let ty::Adt(struct_def, struct_args) = *outer_type.kind() + && struct_def.is_struct() + && let mut fields = struct_def.all_fields() + && let Some(first) = fields.next() + && fields.next().is_none() + && first.vis.is_accessible_from(cx.tcx.parent_module(outer.hir_id), cx.tcx) + { + ( + first.ty(cx.tcx, struct_args), + Sugg::NonParen(format!("{}.{}", outer_sugg.maybe_paren(), first.name).into()), + ) + } else { + (outer_type, outer_sugg) + } + } } impl<'tcx> LateLintPass<'tcx> for Transmute { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { @@ -516,14 +545,17 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { return; } + // A struct having a single pointer can be treated like a pointer. + let (from_field_ty, from_field_expr) = Self::extract_struct_field(cx, e, from_ty, arg); + let linted = wrong_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty) | transmuting_null::check(cx, e, arg, to_ty) | transmute_null_to_fn::check(cx, e, arg, to_ty) - | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) + | transmute_ptr_to_ref::check(cx, e, from_field_ty, to_ty, from_field_expr.clone(), path, self.msrv) | missing_transmute_annotations::check(cx, path, arg, from_ty, to_ty, e.hir_id) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv) + | transmute_ptr_to_ptr::check(cx, e, from_field_ty, to_ty, from_field_expr, self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 91fce5d5bd68a..036b16e3dc3d6 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -14,11 +14,9 @@ pub(super) fn check<'tcx>( e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, - arg: &'tcx Expr<'_>, + arg: sugg::Sugg<'_>, msrv: Msrv, ) -> bool { - let mut applicability = Applicability::MachineApplicable; - let arg_sugg = sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut applicability); match (from_ty.kind(), to_ty.kind()) { (ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => { span_lint_and_then( @@ -34,7 +32,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion_verbose( e.span, "use `pointer::cast` instead", - format!("{}.cast::<{to_pointee_ty}>()", arg_sugg.maybe_paren()), + format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_paren()), Applicability::MaybeIncorrect, ); } else if from_pointee_ty == to_pointee_ty @@ -49,14 +47,14 @@ pub(super) fn check<'tcx>( diag.span_suggestion_verbose( e.span, format!("use `pointer::{method}` instead"), - format!("{}.{method}()", arg_sugg.maybe_paren()), + format!("{}.{method}()", arg.maybe_paren()), Applicability::MaybeIncorrect, ); } else { diag.span_suggestion_verbose( e.span, "use an `as` cast instead", - arg_sugg.as_ty(to_ty), + arg.as_ty(to_ty), Applicability::MaybeIncorrect, ); } diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index e67ab6a73d269..ba107eed6b140 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>( e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, - arg: &'tcx Expr<'_>, + arg: sugg::Sugg<'_>, path: &'tcx Path<'_>, msrv: Msrv, ) -> bool { @@ -27,7 +27,6 @@ pub(super) fn check<'tcx>( e.span, format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), |diag| { - let arg = sugg::Sugg::hir(cx, arg, ".."); let (deref, cast) = match mutbl { Mutability::Mut => ("&mut *", "*mut"), Mutability::Not => ("&*", "*const"), diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index 5d0945bece553..98bf9f9fea586 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -1,9 +1,9 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::visitors::local_used_once; +use clippy_utils::{get_enclosing_block, is_from_proc_macro}; use itertools::Itertools; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind, Node, PatKind}; @@ -11,7 +11,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use std::iter::once; -use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -86,7 +85,7 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & ExprKind::Path(_) => Some(elements.iter().collect()), _ => None, }) - && all_bindings_are_for_conv(cx, &[ty], expr, elements, &locals, ToType::Array) + && all_bindings_are_for_conv(cx, &[ty], elements, &locals, ToType::Array) && !is_from_proc_macro(cx, expr) { span_lint_and_help( @@ -123,7 +122,7 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & ExprKind::Path(_) => Some(elements.iter().collect()), _ => None, }) - && all_bindings_are_for_conv(cx, tys, expr, elements, &locals, ToType::Tuple) + && all_bindings_are_for_conv(cx, tys, elements, &locals, ToType::Tuple) && !is_from_proc_macro(cx, expr) { span_lint_and_help( @@ -148,7 +147,6 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & fn all_bindings_are_for_conv<'tcx>( cx: &LateContext<'tcx>, final_tys: &[Ty<'tcx>], - expr: &Expr<'_>, elements: &[Expr<'_>], locals: &[&Expr<'_>], kind: ToType, @@ -166,13 +164,30 @@ fn all_bindings_are_for_conv<'tcx>( _ => None, }) .all_equal() - // Fix #11124, very convenient utils function! ❤️ - && locals - .iter() - .all(|&l| for_each_local_use_after_expr(cx, l, expr.hir_id, |_| ControlFlow::Break::<()>(())).is_continue()) + && locals.iter().zip(local_parents.iter()).all(|(&l, &parent)| { + if let Node::LetStmt(_) = parent { + return true; + } + + let Some(b) = get_enclosing_block(cx, l) else { + return true; + }; + local_used_once(cx, b, l).is_some() + }) && local_parents.first().is_some_and(|node| { let Some(ty) = match node { - Node::Pat(pat) => Some(pat.hir_id), + Node::Pat(pat) + if let PatKind::Tuple(pats, _) | PatKind::Slice(pats, None, []) = &pat.kind + && pats.iter().zip(locals.iter()).all(|(p, l)| { + if let PatKind::Binding(_, id, _, _) = p.kind { + id == *l + } else { + true + } + }) => + { + Some(pat.hir_id) + }, Node::LetStmt(l) => Some(l.hir_id), _ => None, } @@ -186,7 +201,9 @@ fn all_bindings_are_for_conv<'tcx>( tys.len() == elements.len() && tys.iter().chain(final_tys.iter().copied()).all_equal() }, (ToType::Tuple, ty::Array(ty, len)) => { - let Some(len) = len.try_to_target_usize(cx.tcx) else { return false }; + let Some(len) = len.try_to_target_usize(cx.tcx) else { + return false; + }; len as usize == elements.len() && final_tys.iter().chain(once(ty)).all_equal() }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 8ed3df8731b3f..a95f2b681add0 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -180,14 +180,19 @@ impl Local { field_indices, .. } => { + let field_projections = place + .projections + .iter() + .filter(|proj| matches!(proj.kind, ProjectionKind::Field(_, _))) + .collect::>(); is_potentially_local_place(*local_id, place) // If there were projections other than field projections, err on the side of caution and say that they // _might_ be mutating something. // // The reason we use `<=` and not `==` is that a mutation of `struct` or `struct.field1` should count as // mutation of the child fields such as `struct.field1.field2` - && place.projections.len() <= field_indices.len() - && iter::zip(&place.projections, field_indices.iter().copied().rev()).all(|(proj, field_idx)| { + && field_projections.len() <= field_indices.len() + && iter::zip(&field_projections, field_indices.iter().copied().rev()).all(|(proj, field_idx)| { match proj.kind { ProjectionKind::Field(f_idx, _) => f_idx == field_idx, // If this is a projection we don't expect, it _might_ be mutating something diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 0cf5b9431a342..c06313d1a4c44 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -354,7 +354,10 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { return; } - let sugg = snippet(cx, recv.span, "").into_owned(); + let mut applicability = Applicability::MachineApplicable; + let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "", &mut applicability) + .0 + .into_owned(); span_lint_and_sugg( cx, USELESS_CONVERSION, diff --git a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs index a8351690068df..95085161c09c9 100644 --- a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs @@ -4,10 +4,11 @@ use clippy_utils::source::{snippet, snippet_indent}; use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{ConstArgKind, ExprKind, Node}; +use rustc_hir::{ConstArgKind, Expr, ExprKind, LetStmt, LocalSource, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::IsSuggestable; +use rustc_middle::ty::{IsSuggestable, Ty}; use rustc_session::declare_lint_pass; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -44,7 +45,7 @@ declare_clippy_lint! { declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]); impl LateLintPass<'_> for ZeroRepeatSideEffects { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some(args) = VecArgs::hir(cx, expr) && let VecArgs::Repeat(inner_expr, len) = args && let ExprKind::Lit(l) = len.kind @@ -69,7 +70,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { } } -fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: &'_ rustc_hir::Expr<'_>, is_vec: bool) { +fn inner_check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, inner_expr: &'_ Expr<'_>, is_vec: bool) { // check if expr is a call or has a call inside it if inner_expr.can_have_side_effects() { let parent_hir_node = cx.tcx.parent_hir_node(expr.hir_id); @@ -81,19 +82,22 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: let vec = if is_vec { "vec!" } else { "" }; let (span, sugg) = match parent_hir_node { - Node::LetStmt(l) => ( - l.span, - format!( - "{inner_expr};\n{indent}let {var_name}: {return_type} = {vec}[];", - var_name = snippet(cx, l.pat.span.source_callsite(), "..") - ), - ), + Node::LetStmt(l) + if matches!(l.source, LocalSource::AssignDesugar) + && let mut parent_iter = cx.tcx.hir_parent_iter(l.hir_id) + && let Some((_, Node::Stmt(_))) = parent_iter.next() + && let Some((_, Node::Block(_))) = parent_iter.next() + && let Some((_, Node::Expr(x))) = parent_iter.next() => + { + ( + x.span, + assign_expr_suggestion(cx, x, l.pat.span, &inner_expr, return_type, vec), + ) + }, + Node::LetStmt(l) => (l.span, let_stmt_suggestion(cx, l, &inner_expr, return_type, vec)), Node::Expr(x) if let ExprKind::Assign(l, _, _) = x.kind => ( x.span, - format!( - "{inner_expr};\n{indent}{var_name} = {vec}[] as {return_type}", - var_name = snippet(cx, l.span.source_callsite(), "..") - ), + assign_expr_suggestion(cx, x, l.span, &inner_expr, return_type, vec), ), // NOTE: don't use the stmt span to avoid touching the trailing semicolon Node::Stmt(_) => (expr.span, format!("{inner_expr};\n{indent}{vec}[] as {return_type}")), @@ -131,3 +135,41 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: ); } } + +fn let_stmt_suggestion( + cx: &LateContext<'_>, + let_stmt: &LetStmt<'_>, + inner_expr: &str, + return_type: Ty<'_>, + vec_str: &str, +) -> String { + let indent = snippet_indent(cx, let_stmt.span).unwrap_or_default(); + format!( + "{inner_expr};\n{}let {var_name}: {return_type} = {vec_str}[];", + indent, + var_name = snippet(cx, let_stmt.pat.span.source_callsite(), "..") + ) +} + +fn assign_expr_suggestion( + cx: &LateContext<'_>, + outer_expr: &Expr<'_>, + assign_expr_span: Span, + inner_expr: &str, + return_type: Ty<'_>, + vec_str: &str, +) -> String { + let mut parent_hir_node = cx.tcx.parent_hir_node(outer_expr.hir_id); + if let Node::Stmt(stmt) = parent_hir_node { + parent_hir_node = cx.tcx.parent_hir_node(stmt.hir_id); + } + let needs_curly = !matches!(parent_hir_node, Node::Block(_)); + + let indent = snippet_indent(cx, outer_expr.span).unwrap_or_default(); + let var_name = snippet(cx, assign_expr_span.source_callsite(), ".."); + if needs_curly { + format!("{{\n {indent}{inner_expr};\n {indent}{var_name} = {vec_str}[] as {return_type}\n{indent}}}",) + } else { + format!("{inner_expr};\n{indent}{var_name} = {vec_str}[] as {return_type}") + } +} diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index a1e1b763dccb1..503d581d6c7f9 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.93" +version = "0.1.94" edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" repository = "https://github.com/rust-lang/rust-clippy" @@ -16,6 +16,10 @@ itertools = "0.12" rustc_apfloat = "0.2.0" serde = { version = "1.0", features = ["derive"] } +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = ['cfg(bootstrap)'] + [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] rustc_private = true diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 4b1a10a3d9cfa..dc8695fef9f56 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-11-28 +nightly-2025-12-11 ``` diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 86d17a8231d53..4a7fa3472cae4 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -40,6 +40,7 @@ msrv_aliases! { 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } + 1,67,0 { ILOG2 } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 1d1537dd0e91f..00f4a9c7e5862 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -180,6 +180,7 @@ generate! { has_significant_drop, hidden_glob_reexports, hygiene, + ilog, insert, insert_str, inspect, @@ -207,6 +208,7 @@ generate! { join, kw, lazy_static, + leading_zeros, lint_vec, ln, lock, diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml index b73a7c7bb4d98..ee6d6cdbc34eb 100644 --- a/src/tools/clippy/declare_clippy_lint/Cargo.toml +++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.93" +version = "0.1.94" edition = "2024" repository = "https://github.com/rust-lang/rust-clippy" license = "MIT OR Apache-2.0" diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index 5157b79832a39..1384f4078ebe4 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-11-28" +channel = "nightly-2025-12-11" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/clippy.toml b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/clippy.toml new file mode 100644 index 0000000000000..b6fd0e8a0483e --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/clippy.toml @@ -0,0 +1 @@ +stack-size-threshold = 0 diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs new file mode 100644 index 0000000000000..1f6265590f936 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs @@ -0,0 +1,42 @@ +//@ignore-target: i686 +//@normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR" +//@normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR" + +#![warn(clippy::large_stack_frames)] + +extern crate serde; +use serde::{Deserialize, Serialize}; + +struct ArrayDefault([u8; N]); + +macro_rules! mac { + ($name:ident) => { + fn foo() { + let $name = 1; + println!("macro_name called"); + } + + fn bar() { + let $name = ArrayDefault([0; 1000]); + } + }; +} + +mac!(something); +//~^ large_stack_frames +//~| large_stack_frames + +#[derive(Deserialize, Serialize)] +//~^ large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +struct S { + a: [u128; 31], +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.stderr b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.stderr new file mode 100644 index 0000000000000..bc222f6b10395 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.stderr @@ -0,0 +1,89 @@ +error: function `foo` generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:25:1 + | +LL | fn foo() { + | --- this function has a stack frame size of 20 bytes +... +LL | mac!(something); + | ^^^^^^^^^^^^^^^ + | + = note: 20 bytes is larger than Clippy's configured `stack-size-threshold` of 0 + = note: allocating large amounts of stack space can overflow the stack and cause the program to abort + = note: `-D clippy::large-stack-frames` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]` + +error: function `bar` generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:25:1 + | +LL | fn bar() { + | --- this function has a stack frame size of 2000 bytes +LL | let $name = ArrayDefault([0; 1000]); + | --------- this is the largest part, at 1000 bytes for type `[u8; 1000]` +... +LL | mac!(something); + | ^^^^^^^^^^^^^^^ + | + = note: 2000 bytes is larger than Clippy's configured `stack-size-threshold` of 0 + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:23 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^ + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames_for_special_targets/clippy.toml b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_special_targets/clippy.toml new file mode 100644 index 0000000000000..02f3bc02dc4b7 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_special_targets/clippy.toml @@ -0,0 +1,2 @@ +stack-size-threshold = 0 +allow-large-stack-frames-in-tests = false diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames_for_special_targets/large_stack_frames.rs b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_special_targets/large_stack_frames.rs new file mode 100644 index 0000000000000..cc01232ca4089 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/large_stack_frames_for_special_targets/large_stack_frames.rs @@ -0,0 +1,13 @@ +// This test checks if `clippy::large_stack_frames` is working correctly when encountering functions +// generated by special compiling targets like `--test`. +//@compile-flags: --test +//@check-pass + +#![warn(clippy::large_stack_frames)] + +#[cfg(test)] +#[expect(clippy::large_stack_frames)] +mod test { + #[test] + fn main_test() {} +} diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed index 419e62f92f469..3683e826aa925 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -1,6 +1,7 @@ //@aux-build:proc_macro_derive.rs #![warn(clippy::nonstandard_macro_braces)] +#![allow(clippy::println_empty_string)] extern crate proc_macro_derive; extern crate quote; @@ -75,3 +76,16 @@ fn issue9913() { [0]; // separate statement, not indexing into the result of println. //~^^ nonstandard_macro_braces } + +fn issue15594() { + println!(); + println!(""); + println!(); + //~^ nonstandard_macro_braces + println!(""); + //~^ nonstandard_macro_braces + println!(); + //~^ nonstandard_macro_braces + println!(""); + //~^ nonstandard_macro_braces +} diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index b0bbced4ea3c2..c1779dceff172 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -1,6 +1,7 @@ //@aux-build:proc_macro_derive.rs #![warn(clippy::nonstandard_macro_braces)] +#![allow(clippy::println_empty_string)] extern crate proc_macro_derive; extern crate quote; @@ -75,3 +76,16 @@ fn issue9913() { [0]; // separate statement, not indexing into the result of println. //~^^ nonstandard_macro_braces } + +fn issue15594() { + println!(); + println!(""); + println![]; + //~^ nonstandard_macro_braces + println![""]; + //~^ nonstandard_macro_braces + println! {}; + //~^ nonstandard_macro_braces + println! {""}; + //~^ nonstandard_macro_braces +} diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index 87325f05c9bcd..2488f7fa01e5b 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -1,5 +1,5 @@ error: use of irregular braces for `vec!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:44:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:45:13 | LL | let _ = vec! {1, 2, 3}; | ^^^^^^^^^^^^^^ help: consider writing: `vec![1, 2, 3]` @@ -8,31 +8,31 @@ LL | let _ = vec! {1, 2, 3}; = help: to override `-D warnings` add `#[allow(clippy::nonstandard_macro_braces)]` error: use of irregular braces for `format!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:46:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:47:13 | LL | let _ = format!["ugh {} stop being such a good compiler", "hello"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `format!("ugh {} stop being such a good compiler", "hello")` error: use of irregular braces for `matches!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:48:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:49:13 | LL | let _ = matches!{{}, ()}; | ^^^^^^^^^^^^^^^^ help: consider writing: `matches!({}, ())` error: use of irregular braces for `quote!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:50:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:51:13 | LL | let _ = quote!(let x = 1;); | ^^^^^^^^^^^^^^^^^^ help: consider writing: `quote!{let x = 1;}` error: use of irregular braces for `quote::quote!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:52:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:53:13 | LL | let _ = quote::quote!(match match match); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `quote::quote!{match match match}` error: use of irregular braces for `vec!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:18:9 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:19:9 | LL | vec!{0, 0, 0} | ^^^^^^^^^^^^^ help: consider writing: `vec![0, 0, 0]` @@ -43,22 +43,46 @@ LL | let _ = test!(); // trigger when macro def is inside our own crate = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of irregular braces for `type_pos!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:62:12 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:63:12 | LL | let _: type_pos!(usize) = vec![]; | ^^^^^^^^^^^^^^^^ help: consider writing: `type_pos![usize]` error: use of irregular braces for `eprint!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:65:5 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:66:5 | LL | eprint!("test if user config overrides defaults"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `eprint!["test if user config overrides defaults"]` error: use of irregular braces for `println!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:74:5 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:75:5 | LL | println! {"hello world"} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `println!("hello world");` -error: aborting due to 9 previous errors +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:83:5 + | +LL | println![]; + | ^^^^^^^^^^ help: consider writing: `println!()` + +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:85:5 + | +LL | println![""]; + | ^^^^^^^^^^^^ help: consider writing: `println!("")` + +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:87:5 + | +LL | println! {}; + | ^^^^^^^^^^^ help: consider writing: `println!()` + +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:89:5 + | +LL | println! {""}; + | ^^^^^^^^^^^^^ help: consider writing: `println!("")` + +error: aborting due to 13 previous errors 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 d5040f4a39bfd..e208bd510657e 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 @@ -9,6 +9,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests + allow-large-stack-frames-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests @@ -107,6 +108,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests + allow-large-stack-frames-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests @@ -205,6 +207,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests + allow-large-stack-frames-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed index bfe826508f36e..a4689a7840cea 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::ptr_offset_by_literal)] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs index ce248f157c6ef..d7468f37a3a49 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::ptr_offset_by_literal)] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs index c6476a7507a1d..bab20b091d389 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs @@ -472,3 +472,22 @@ fn issue15321() { //~^ unnecessary_unwrap } } + +mod issue16188 { + struct Foo { + value: Option, + } + + impl Foo { + pub fn bar(&mut self) { + let print_value = |v: i32| { + println!("{}", v); + }; + + if self.value.is_none() { + self.value = Some(10); + print_value(self.value.unwrap()); + } + } + } +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-4579.rs b/src/tools/clippy/tests/ui/crashes/ice-4579.rs index 14c8113e315b7..a2592e74c66d1 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4579.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4579.rs @@ -1,6 +1,6 @@ //@ check-pass -#![allow(clippy::single_match)] +#![allow(clippy::single_match, clippy::ptr_offset_by_literal)] use std::ptr; diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.rs b/src/tools/clippy/tests/ui/crashes/ice-9041.rs index 4b2a0f9531148..fae3233ba2f51 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.rs @@ -1,3 +1,4 @@ +#![warn(clippy::search_is_some)] pub struct Thing; //@no-rustfix pub fn has_thing(things: &[Thing]) -> bool { diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr index dd9db71c5de83..256c8b8330344 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/crashes/ice-9041.rs:5:19 + --> tests/ui/crashes/ice-9041.rs:6:19 | LL | things.iter().find(|p| is_thing_ready(p)).is_some() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|p| is_thing_ready(&p))` diff --git a/src/tools/clippy/tests/ui/decimal_bitwise_operands.rs b/src/tools/clippy/tests/ui/decimal_bitwise_operands.rs new file mode 100644 index 0000000000000..f1c053bb4358a --- /dev/null +++ b/src/tools/clippy/tests/ui/decimal_bitwise_operands.rs @@ -0,0 +1,133 @@ +#![allow( + clippy::erasing_op, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::unnecessary_cast, + clippy::op_ref +)] +#![warn(clippy::decimal_bitwise_operands)] + +macro_rules! bitwise_op { + ($x:expr, $y:expr) => { + $x & $y; + }; +} + +pub const SOME_CONST: i32 = 12345; + +fn main() { + let mut x = 0; + // BAD: Bitwise operation, decimal literal, one literal + x & 9_8765_4321; //~ decimal_bitwise_operands + x & 100_i32; //~ decimal_bitwise_operands + x | (/* comment */99); //~ decimal_bitwise_operands + x ^ (99); //~ decimal_bitwise_operands + x &= 99; //~ decimal_bitwise_operands + x |= { 99 }; //~ decimal_bitwise_operands + x |= { { 99 } }; //~ decimal_bitwise_operands + x |= { + 0b1000; + 99 //~ decimal_bitwise_operands + }; + x ^= (99); //~ decimal_bitwise_operands + + // BAD: Bitwise operation, decimal literal, two literals + 0b1010 & 99; //~ decimal_bitwise_operands + 0b1010 | (99); //~ decimal_bitwise_operands + 0b1010 ^ (/* comment */99); //~ decimal_bitwise_operands + 99 & 0b1010; //~ decimal_bitwise_operands + (99) | 0b1010; //~ decimal_bitwise_operands + (/* comment */99) ^ 0b1010; //~ decimal_bitwise_operands + 0xD | { 99 }; //~ decimal_bitwise_operands + 88 & 99; + //~^ decimal_bitwise_operands + //~| decimal_bitwise_operands + 37 & 38 & 39; + //~^ decimal_bitwise_operands + //~| decimal_bitwise_operands + //~| decimal_bitwise_operands + + // GOOD: Bitwise operation, binary/hex/octal literal, one literal + x & 0b1010; + x | 0b1010; + x ^ 0b1010; + x &= 0b1010; + x |= 0b1010; + x ^= 0b1010; + x & 0xD; + x & 0o77; + x | 0o123; + x ^ 0o377; + x &= 0o777; + x |= 0o7; + x ^= 0o70; + + // GOOD: Bitwise operation, binary/hex/octal literal, two literals + 0b1010 & 0b1101; + 0xD ^ 0xF; + 0o377 ^ 0o77; + 0b1101 ^ 0xFF; + + // GOOD: Numeric operation, any literal + x += 99; + x -= 0b1010; + x *= 0xD; + 99 + 99; + 0b1010 - 0b1101; + 0xD * 0xD; + + // BAD: Unary, cast and reference, decimal literal + x & !100; //~ decimal_bitwise_operands + x & -100; //~ decimal_bitwise_operands + x & (100 as i32); //~ decimal_bitwise_operands + x & &100; //~ decimal_bitwise_operands + + // GOOD: Unary, cast and reference, non-decimal literal + x & !0b1101; + x & -0xD; + x & (0o333 as i32); + x & &0b1010; + + // GOOD: Bitwise operation, variables only + let y = 0; + x & y; + x &= y; + x + y; + x += y; + + // GOOD: Macro expansion (should be ignored) + bitwise_op!(x, 123); + bitwise_op!(0b1010, 123); + + // GOOD: Using const (should be ignored) + x & SOME_CONST; + x |= SOME_CONST; + + // GOOD: Parenthesized binary/hex literal (should not trigger lint) + x & (0b1111); + x |= (0b1010); + x ^ (/* comment */0b1100); + (0xFF) & x; + + // GOOD: Power of two and power of two minus one + x & 16; // 2^4 + x | (31); // 2^5 - 1 + x ^ 0x40; // 2^6 (hex) + x ^= 7; // 2^3 - 1 + + // GOOD: Bitwise operation, single digit decimal literal + 5 & 9; + x ^ 6; + x ^= 7; + + // GOOD: More complex expressions + (x + 1) & 0xFF; + (x * 2) | (y & 0xF); + (x ^ y) & 0b11110000; + x | (1 << 9); + + // GOOD: Special cases + x & 0; // All bits off + x | !0; // All bits on + x ^ 1; // Toggle LSB +} diff --git a/src/tools/clippy/tests/ui/decimal_bitwise_operands.stderr b/src/tools/clippy/tests/ui/decimal_bitwise_operands.stderr new file mode 100644 index 0000000000000..1b2b7bb71b69c --- /dev/null +++ b/src/tools/clippy/tests/ui/decimal_bitwise_operands.stderr @@ -0,0 +1,204 @@ +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:21:9 + | +LL | x & 9_8765_4321; + | ^^^^^^^^^^^ + | + = help: use binary (0b11_1010_1101_1110_0110_1000_1011_0001), hex (0x3ade_68b1), or octal (0o7_267_464_261) notation for better readability + = note: `-D clippy::decimal-bitwise-operands` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::decimal_bitwise_operands)]` + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:22:9 + | +LL | x & 100_i32; + | ^^^^^^^ + | + = help: use binary (0b110_0100_i32), hex (0x0064_i32), or octal (0o144_i32) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:23:23 + | +LL | x | (/* comment */99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:24:10 + | +LL | x ^ (99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:25:10 + | +LL | x &= 99; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:26:12 + | +LL | x |= { 99 }; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:27:14 + | +LL | x |= { { 99 } }; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:30:9 + | +LL | 99 + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:32:11 + | +LL | x ^= (99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:35:14 + | +LL | 0b1010 & 99; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:36:15 + | +LL | 0b1010 | (99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:37:28 + | +LL | 0b1010 ^ (/* comment */99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:38:5 + | +LL | 99 & 0b1010; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:39:6 + | +LL | (99) | 0b1010; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:40:19 + | +LL | (/* comment */99) ^ 0b1010; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:41:13 + | +LL | 0xD | { 99 }; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:42:5 + | +LL | 88 & 99; + | ^^ + | + = help: use binary (0b101_1000), hex (0x0058), or octal (0o130) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:42:10 + | +LL | 88 & 99; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:45:15 + | +LL | 37 & 38 & 39; + | ^^ + | + = help: use binary (0b10_0111), hex (0x0027), or octal (0o47) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:45:5 + | +LL | 37 & 38 & 39; + | ^^ + | + = help: use binary (0b10_0101), hex (0x0025), or octal (0o45) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:45:10 + | +LL | 37 & 38 & 39; + | ^^ + | + = help: use binary (0b10_0110), hex (0x0026), or octal (0o46) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:80:10 + | +LL | x & !100; + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:81:10 + | +LL | x & -100; + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:82:10 + | +LL | x & (100 as i32); + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:83:10 + | +LL | x & &100; + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: aborting due to 25 previous errors + diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index cd225da611c48..fa70371b926fe 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -61,7 +61,7 @@ error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can n LL | #![warn(clippy::should_assert_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::string_to_string` has been removed: `clippy:implicit_clone` covers those cases +error: lint `clippy::string_to_string` has been removed: `clippy::implicit_clone` covers those cases --> tests/ui/deprecated.rs:15:9 | LL | #![warn(clippy::string_to_string)] diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed index f2df9f0204ea6..1e36ca4f1f096 100644 --- a/src/tools/clippy/tests/ui/entry.fixed +++ b/src/tools/clippy/tests/ui/entry.fixed @@ -248,4 +248,28 @@ mod issue14449 { } } +// Don't suggest when it would cause `MutexGuard` to be held across an await point. +mod issue_16173 { + use std::collections::HashMap; + use std::sync::Mutex; + + async fn f() {} + + async fn foo() { + let mu_map = Mutex::new(HashMap::new()); + if !mu_map.lock().unwrap().contains_key(&0) { + f().await; + mu_map.lock().unwrap().insert(0, 0); + } + + if mu_map.lock().unwrap().contains_key(&1) { + todo!(); + } else { + mu_map.lock().unwrap().insert(1, 42); + todo!(); + f().await; + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs index 166eea417ac23..b3da0ef3ffd69 100644 --- a/src/tools/clippy/tests/ui/entry.rs +++ b/src/tools/clippy/tests/ui/entry.rs @@ -254,4 +254,28 @@ mod issue14449 { } } +// Don't suggest when it would cause `MutexGuard` to be held across an await point. +mod issue_16173 { + use std::collections::HashMap; + use std::sync::Mutex; + + async fn f() {} + + async fn foo() { + let mu_map = Mutex::new(HashMap::new()); + if !mu_map.lock().unwrap().contains_key(&0) { + f().await; + mu_map.lock().unwrap().insert(0, 0); + } + + if mu_map.lock().unwrap().contains_key(&1) { + todo!(); + } else { + mu_map.lock().unwrap().insert(1, 42); + todo!(); + f().await; + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs index 011833072d762..509348628dd67 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty.rs +++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs @@ -473,4 +473,16 @@ impl Alias2 { } } +// Issue #16190 +pub struct RefMutLenButRefIsEmpty; +impl RefMutLenButRefIsEmpty { + pub fn len(&mut self) -> usize { + todo!() + } + + pub fn is_empty(&self) -> bool { + todo!() + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_ilog2.fixed b/src/tools/clippy/tests/ui/manual_ilog2.fixed new file mode 100644 index 0000000000000..a0f6d9392c303 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_ilog2.fixed @@ -0,0 +1,32 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::manual_ilog2)] +#![allow(clippy::unnecessary_operation)] + +use proc_macros::{external, with_span}; + +fn foo(a: u32, b: u64) { + a.ilog2(); //~ manual_ilog2 + a.ilog2(); //~ manual_ilog2 + + b.ilog2(); //~ manual_ilog2 + 64 - b.leading_zeros(); // No lint because manual ilog2 is `BIT_WIDTH - 1 - x.leading_zeros()` + + // don't lint when macros are involved + macro_rules! two { + () => { + 2 + }; + }; + + macro_rules! thirty_one { + () => { + 31 + }; + }; + + a.ilog(two!()); + thirty_one!() - a.leading_zeros(); + + external!($a.ilog(2)); + with_span!(span; a.ilog(2)); +} diff --git a/src/tools/clippy/tests/ui/manual_ilog2.rs b/src/tools/clippy/tests/ui/manual_ilog2.rs new file mode 100644 index 0000000000000..bd4b5d9d3c0d7 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_ilog2.rs @@ -0,0 +1,32 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::manual_ilog2)] +#![allow(clippy::unnecessary_operation)] + +use proc_macros::{external, with_span}; + +fn foo(a: u32, b: u64) { + 31 - a.leading_zeros(); //~ manual_ilog2 + a.ilog(2); //~ manual_ilog2 + + 63 - b.leading_zeros(); //~ manual_ilog2 + 64 - b.leading_zeros(); // No lint because manual ilog2 is `BIT_WIDTH - 1 - x.leading_zeros()` + + // don't lint when macros are involved + macro_rules! two { + () => { + 2 + }; + }; + + macro_rules! thirty_one { + () => { + 31 + }; + }; + + a.ilog(two!()); + thirty_one!() - a.leading_zeros(); + + external!($a.ilog(2)); + with_span!(span; a.ilog(2)); +} diff --git a/src/tools/clippy/tests/ui/manual_ilog2.stderr b/src/tools/clippy/tests/ui/manual_ilog2.stderr new file mode 100644 index 0000000000000..7c9694f353301 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_ilog2.stderr @@ -0,0 +1,23 @@ +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:8:5 + | +LL | 31 - a.leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.ilog2()` + | + = note: `-D clippy::manual-ilog2` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_ilog2)]` + +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:9:5 + | +LL | a.ilog(2); + | ^^^^^^^^^ help: try: `a.ilog2()` + +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:11:5 + | +LL | 63 - b.leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `b.ilog2()` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed index 304be05f6c4cf..8dd142b2c79ac 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed @@ -58,3 +58,13 @@ fn main() { let _ = 1i8.checked_sub(1).unwrap_or(127); // ok let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok } + +fn issue15655() { + let _ = 5u32.saturating_sub(1u32); //~ manual_saturating_arithmetic + let _ = 5u32.checked_add(1u32).unwrap_or_default(); // ok + let _ = 5u32.checked_mul(1u32).unwrap_or_default(); // ok + + let _ = 5i32.checked_sub(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_add(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_mul(1i32).unwrap_or_default(); // ok +} diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs index c2b570e974ac8..9cc8bc42410da 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs @@ -73,3 +73,13 @@ fn main() { let _ = 1i8.checked_sub(1).unwrap_or(127); // ok let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok } + +fn issue15655() { + let _ = 5u32.checked_sub(1u32).unwrap_or_default(); //~ manual_saturating_arithmetic + let _ = 5u32.checked_add(1u32).unwrap_or_default(); // ok + let _ = 5u32.checked_mul(1u32).unwrap_or_default(); // ok + + let _ = 5i32.checked_sub(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_add(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_mul(1i32).unwrap_or_default(); // ok +} diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr index 2f006a3ae1702..aec0f0a164198 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr @@ -165,5 +165,11 @@ LL | | .checked_sub(-1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); | |_______________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(-1)` -error: aborting due to 24 previous errors +error: manual saturating arithmetic + --> tests/ui/manual_saturating_arithmetic.rs:78:13 + | +LL | let _ = 5u32.checked_sub(1u32).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `5u32.saturating_sub(1u32)` + +error: aborting due to 25 previous errors diff --git a/src/tools/clippy/tests/ui/match_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_like_matches_macro.fixed index a1c95e8a94f14..dad59c1ce6e4d 100644 --- a/src/tools/clippy/tests/ui/match_like_matches_macro.fixed +++ b/src/tools/clippy/tests/ui/match_like_matches_macro.fixed @@ -223,3 +223,10 @@ fn msrv_1_42() { let _y = matches!(Some(5), Some(0)); //~^^^^ match_like_matches_macro } + +#[expect(clippy::option_option)] +fn issue15841(opt: Option>>, value: i32) { + // Lint: no if-let _in the guard_ + let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); + //~^^^^ match_like_matches_macro +} diff --git a/src/tools/clippy/tests/ui/match_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_like_matches_macro.rs index eb419ba5bf8de..94bc6433e5cb7 100644 --- a/src/tools/clippy/tests/ui/match_like_matches_macro.rs +++ b/src/tools/clippy/tests/ui/match_like_matches_macro.rs @@ -267,3 +267,13 @@ fn msrv_1_42() { }; //~^^^^ match_like_matches_macro } + +#[expect(clippy::option_option)] +fn issue15841(opt: Option>>, value: i32) { + // Lint: no if-let _in the guard_ + let _ = match opt { + Some(first) if (if let Some(second) = first { true } else { todo!() }) => true, + _ => false, + }; + //~^^^^ match_like_matches_macro +} diff --git a/src/tools/clippy/tests/ui/match_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_like_matches_macro.stderr index ae277ce4dca68..a8e352461dbb6 100644 --- a/src/tools/clippy/tests/ui/match_like_matches_macro.stderr +++ b/src/tools/clippy/tests/ui/match_like_matches_macro.stderr @@ -6,10 +6,18 @@ LL | let _y = match x { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `matches!(x, Some(0))` + | |_____^ | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]` +help: use `matches!` directly + | +LL - let _y = match x { +LL - Some(0) => true, +LL - _ => false, +LL - }; +LL + let _y = matches!(x, Some(0)); + | error: redundant pattern matching, consider using `is_some()` --> tests/ui/match_like_matches_macro.rs:20:14 @@ -42,13 +50,28 @@ LL | let _zz = match x { LL | | Some(r) if r == 0 => false, LL | | _ => true, LL | | }; - | |_____^ help: try: `!matches!(x, Some(r) if r == 0)` + | |_____^ + | +help: use `matches!` directly + | +LL - let _zz = match x { +LL - Some(r) if r == 0 => false, +LL - _ => true, +LL - }; +LL + let _zz = !matches!(x, Some(r) if r == 0); + | -error: if let .. else expression looks like `matches!` macro +error: `if let .. else` expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:41:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!` directly + | +LL - let _zzz = if let Some(5) = x { true } else { false }; +LL + let _zzz = matches!(x, Some(5)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:66:20 @@ -59,7 +82,17 @@ LL | | E::A(_) => true, LL | | E::B(_) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _ans = match x { +LL - E::A(_) => true, +LL - E::B(_) => true, +LL - _ => false, +LL - }; +LL + let _ans = matches!(x, E::A(_) | E::B(_)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:77:20 @@ -71,7 +104,19 @@ LL | | true ... | LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _ans = match x { +LL - E::A(_) => { +LL - true +LL - } +LL - E::B(_) => true, +LL - _ => false, +LL - }; +LL + let _ans = matches!(x, E::A(_) | E::B(_)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:88:20 @@ -82,7 +127,17 @@ LL | | E::B(_) => false, LL | | E::C => false, LL | | _ => true, LL | | }; - | |_________^ help: try: `!matches!(x, E::B(_) | E::C)` + | |_________^ + | +help: use `matches!` directly + | +LL - let _ans = match x { +LL - E::B(_) => false, +LL - E::C => false, +LL - _ => true, +LL - }; +LL + let _ans = !matches!(x, E::B(_) | E::C); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:149:18 @@ -92,7 +147,16 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(z, Some(3))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _z = match &z { +LL - Some(3) => true, +LL - _ => false, +LL - }; +LL + let _z = matches!(z, Some(3)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:159:18 @@ -102,7 +166,16 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(&z, Some(3))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _z = match &z { +LL - Some(3) => true, +LL - _ => false, +LL - }; +LL + let _z = matches!(&z, Some(3)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:177:21 @@ -112,7 +185,16 @@ LL | let _ = match &z { LL | | AnEnum::X => true, LL | | _ => false, LL | | }; - | |_____________^ help: try: `matches!(&z, AnEnum::X)` + | |_____________^ + | +help: use `matches!` directly + | +LL - let _ = match &z { +LL - AnEnum::X => true, +LL - _ => false, +LL - }; +LL + let _ = matches!(&z, AnEnum::X); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:192:20 @@ -122,7 +204,16 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(&val, &Some(ref _a))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _res = match &val { +LL - &Some(ref _a) => true, +LL - _ => false, +LL - }; +LL + let _res = matches!(&val, &Some(ref _a)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:205:20 @@ -132,7 +223,16 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(&val, &Some(ref _a))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _res = match &val { +LL - &Some(ref _a) => true, +LL - _ => false, +LL - }; +LL + let _res = matches!(&val, &Some(ref _a)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:264:14 @@ -142,7 +242,35 @@ LL | let _y = match Some(5) { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `matches!(Some(5), Some(0))` + | |_____^ + | +help: use `matches!` directly + | +LL - let _y = match Some(5) { +LL - Some(0) => true, +LL - _ => false, +LL - }; +LL + let _y = matches!(Some(5), Some(0)); + | + +error: match expression looks like `matches!` macro + --> tests/ui/match_like_matches_macro.rs:274:13 + | +LL | let _ = match opt { + | _____________^ +LL | | Some(first) if (if let Some(second) = first { true } else { todo!() }) => true, +LL | | _ => false, +LL | | }; + | |_____^ + | +help: use `matches!` directly + | +LL - let _ = match opt { +LL - Some(first) if (if let Some(second) = first { true } else { todo!() }) => true, +LL - _ => false, +LL - }; +LL + let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); + | -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/match_like_matches_macro_if_let_guard.rs b/src/tools/clippy/tests/ui/match_like_matches_macro_if_let_guard.rs new file mode 100644 index 0000000000000..b596d36072e53 --- /dev/null +++ b/src/tools/clippy/tests/ui/match_like_matches_macro_if_let_guard.rs @@ -0,0 +1,51 @@ +//@check-pass +#![warn(clippy::match_like_matches_macro)] +#![feature(if_let_guard)] + +#[expect(clippy::option_option)] +fn issue15841(opt: Option>>, value: i32) { + let _ = match opt { + Some(first) + if let Some(second) = first + && let Some(third) = second + && third == value => + { + true + }, + _ => false, + }; + + // if-let is the second if + let _ = match opt { + Some(first) + if first.is_some() + && let Some(second) = first => + { + true + }, + _ => false, + }; + + // if-let is the third if + let _ = match opt { + Some(first) + if first.is_some() + && first.is_none() + && let Some(second) = first => + { + true + }, + _ => false, + }; + + // don't get confused by `or`s + let _ = match opt { + Some(first) + if (first.is_some() || first.is_none()) + && let Some(second) = first => + { + true + }, + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr index b686eda7530a0..d5b5455343e43 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr @@ -1,407 +1,191 @@ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:30:5 | -LL | assert!(v.len() < 5); - | -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:5 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:12 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:26 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ = note: asserting the length before indexing will elide bounds checks = note: `-D clippy::missing-asserts-for-indexing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]` - -error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:36:5 +help: provide the highest index that is indexed with | -LL | assert!(v.len() <= 5); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL - assert!(v.len() < 5); +LL + assert!(v.len() > 4); | -note: slice indexed here + +error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:36:5 | LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:12 + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:19 +help: provide the highest index that is indexed with | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:26 +LL - assert!(v.len() <= 5); +LL + assert!(v.len() > 4); | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:42:5 | -LL | assert!(v.len() > 3); - | -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:5 + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:12 +help: provide the highest index that is indexed with | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:26 +LL - assert!(v.len() > 3); +LL + assert!(v.len() > 4); | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:48:5 | -LL | assert!(v.len() >= 4); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:5 - | LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:12 + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:19 +help: provide the highest index that is indexed with | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:26 +LL - assert!(v.len() >= 4); +LL + assert!(v.len() > 4); | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:66:13 | -LL | assert!(v.len() >= 3); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 3)` -LL | let _ = v[0]; - | _____________^ -... | -LL | | let _ = v[1..4]; - | |___________________^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:66:13 - | LL | let _ = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:69:13 - | +... LL | let _ = v[1..4]; | ^^^^^^^ - = note: asserting the length before indexing will elide bounds checks - -error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:81:13 | -LL | assert!(v.len() >= 4); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` -LL | let _ = v[0]; - | _____________^ -... | -LL | | let _ = v[1..=4]; - | |____________________^ +help: provide the highest index that is indexed with | -note: slice indexed here +LL - assert!(v.len() >= 3); +LL + assert!(v.len() > 3); + | + +error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:81:13 | LL | let _ = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:84:13 - | +... LL | let _ = v[1..=4]; | ^^^^^^^^ - = note: asserting the length before indexing will elide bounds checks + | +help: provide the highest index that is indexed with + | +LL - assert!(v.len() >= 4); +LL + assert!(v.len() > 4); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:97:13 | -LL | assert!(v1.len() >= 12); - | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` -LL | assert!(v2.len() >= 15); LL | let _ = v1[0] + v1[12]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:97:13 +help: provide the highest index that is indexed with | -LL | let _ = v1[0] + v1[12]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:97:21 +LL - assert!(v1.len() >= 12); +LL + assert!(v1.len() > 12); | -LL | let _ = v1[0] + v1[12]; - | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:100:13 | -LL | assert!(v2.len() >= 15); - | ----------------------- help: provide the highest index that is indexed with: `assert!(v2.len() > 15)` -... LL | let _ = v2[5] + v2[15]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:100:13 +help: provide the highest index that is indexed with | -LL | let _ = v2[5] + v2[15]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:100:21 +LL - assert!(v2.len() >= 15); +LL + assert!(v2.len() > 15); | -LL | let _ = v2[5] + v2[15]; - | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:106:13 | -LL | assert!(v1.len() >= 12); - | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` -LL | assert!(v2.len() > 15); LL | let _ = v1[0] + v1[12]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:106:13 +help: provide the highest index that is indexed with | -LL | let _ = v1[0] + v1[12]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:106:21 +LL - assert!(v1.len() >= 12); +LL + assert!(v1.len() > 12); | -LL | let _ = v1[0] + v1[12]; - | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:131:13 | -LL | assert!(v1.len() == 2); - | ---------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` -... LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ ^^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:13 +help: provide the highest index that is indexed with | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:21 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:29 +LL - assert!(v1.len() == 2); +LL + assert!(v1.len() == 3); | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:136:13 | -LL | assert!(2 == v3.len()); - | ---------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` -... LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ ^^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:13 +help: provide the highest index that is indexed with | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:21 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:29 +LL - assert!(2 == v3.len()); +LL + assert!(v3.len() == 3); | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:158:13 | -LL | assert_eq!(v1.len(), 2); - | ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v1.len(), 3)` -... LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ ^^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:13 +help: provide the highest index that is indexed with | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:21 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:29 +LL - assert_eq!(v1.len(), 2); +LL + assert_eq!(v1.len(), 3); | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:163:13 | -LL | assert_eq!(2, v3.len()); - | ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v3.len(), 3)` -... LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ ^^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:13 +help: provide the highest index that is indexed with | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:21 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:29 +LL - assert_eq!(2, v3.len()); +LL + assert_eq!(v3.len(), 3); | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:172:17 | -LL | assert_eq!(v.len(), 2); - | ---------------------- help: provide the highest index that is indexed with: `assert_eq!(v.len(), 3)` LL | let _ = v[0] + v[1] + v[2]; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^ ^^^^ ^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:172:17 +help: provide the highest index that is indexed with | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:172:24 +LL - assert_eq!(v.len(), 2); +LL + assert_eq!(v.len(), 3); | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:172:31 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:178:17 | -LL | debug_assert_eq!(v.len(), 2); - | ---------------------------- help: provide the highest index that is indexed with: `debug_assert_eq!(v.len(), 3)` LL | let _ = v[0] + v[1] + v[2]; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^ ^^^^ ^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:178:17 +help: provide the highest index that is indexed with | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:178:24 +LL - debug_assert_eq!(v.len(), 2); +LL + debug_assert_eq!(v.len(), 3); | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:178:31 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr index a17ad02321386..2929646494a41 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -2,34 +2,9 @@ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:5 | LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | = help: consider asserting the length before indexing: `assert!(v.len() > 4);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:5 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:12 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:26 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ = note: asserting the length before indexing will elide bounds checks = note: `-D clippy::missing-asserts-for-indexing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]` @@ -37,191 +12,82 @@ LL | v[0] + v[1] + v[2] + v[3] + v[4] error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:10:13 | -LL | let _ = v[0]; - | _____________^ -... | -LL | | let _ = v[1..4]; - | |___________________^ - | - = help: consider asserting the length before indexing: `assert!(v.len() > 3);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:10:13 - | LL | let _ = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:13:13 - | +... LL | let _ = v[1..4]; | ^^^^^^^ - = note: asserting the length before indexing will elide bounds checks + | + = help: consider asserting the length before indexing: `assert!(v.len() > 3);` error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 | -LL | let a = v[0]; - | _____________^ -LL | | -LL | | -LL | | let b = v[1]; -LL | | let c = v[2]; - | |________________^ - | - = help: consider asserting the length before indexing: `assert!(v.len() > 2);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 - | LL | let a = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:20:13 - | +... LL | let b = v[1]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:21:13 - | LL | let c = v[2]; | ^^^^ - = note: asserting the length before indexing will elide bounds checks + | + = help: consider asserting the length before indexing: `assert!(v.len() > 2);` error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 | LL | let _ = v1[0] + v1[12]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(v1.len() > 12);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:21 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 | LL | let _ = v2[5] + v2[15]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:21 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 | LL | let _ = v2[5] + v2[15]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:21 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 | LL | let _ = f.v[0] + f.v[1]; - | ^^^^^^^^^^^^^^^ + | ^^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(f.v.len() > 1);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 - | -LL | let _ = f.v[0] + f.v[1]; - | ^^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:22 - | -LL | let _ = f.v[0] + f.v[1]; - | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 | LL | let _ = x[0] + x[1]; - | ^^^^^^^^^^^ + | ^^^^ ^^^^ | = help: consider asserting the length before indexing: `assert!(x.len() > 1);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 - | -LL | let _ = x[0] + x[1]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:20 - | -LL | let _ = x[0] + x[1]; - | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 | LL | let _ = v1[1] + v1[2]; - | ^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ | = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 - | -LL | let _ = v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:21 - | -LL | let _ = v1[1] + v1[2]; - | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 | LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ ^^^^^ | = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:21 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:29 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/needless_type_cast.fixed b/src/tools/clippy/tests/ui/needless_type_cast.fixed new file mode 100644 index 0000000000000..32c348d3ca3aa --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_type_cast.fixed @@ -0,0 +1,182 @@ +#![warn(clippy::needless_type_cast)] +#![allow(clippy::no_effect, clippy::unnecessary_cast, unused)] + +fn takes_i32(x: i32) -> i32 { + x +} + +fn generic(x: T) -> T { + x +} + +fn main() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = a as i32 + 5; + let _ = a as i32 * 2; + + let b: u16 = 20; + let _ = b; + let _ = b as u32; + + let c: u8 = 5; + let _ = c as u16; + let _ = c as u32; + + let d: i32 = 100; + let _ = d + 1; + + let e = 42u8; + let _ = e as i64; + let _ = e as i64 + 10; + + let f: usize = 1; + //~^ needless_type_cast + let _ = f as usize; +} + +fn test_function_call() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = takes_i32(a as i32); + let _ = takes_i32(a as i32); +} + +fn test_generic_call() { + let a: u8 = 10; + let _ = generic(a as i32); + let _ = generic(a as i32); +} + +fn test_method_on_cast() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = (a as i32).checked_add(5); + let _ = (a as i32).saturating_mul(2); +} + +fn test_iterator_sum() { + let a: i32 = 10; + //~^ needless_type_cast + let arr = [a as i32, a as i32]; + let _: i32 = arr.iter().copied().sum(); +} + +fn test_closure() { + let a: i32 = 10; + //~^ needless_type_cast + let _: i32 = [1i32, 2].iter().map(|x| x + a as i32).sum(); +} + +fn test_struct_field() { + struct S { + x: i32, + y: i32, + } + + let a: i32 = 10; + //~^ needless_type_cast + let _ = S { + x: a as i32, + y: a as i32, + }; +} + +fn test_option() { + let a: u8 = 10; + let _: Option = Some(a as i32); + let _: Option = Some(a as i32); +} + +fn test_mixed_context() { + let a: u8 = 10; + let _ = takes_i32(a as i32); + let _ = generic(a as i32); +} + +fn test_nested_block() { + if true { + let a: i32 = 10; + //~^ needless_type_cast + let _ = a as i32 + 1; + let _ = a as i32 * 2; + } +} + +fn test_match_expr() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = match 1 { + 1 => a as i32, + _ => a as i32, + }; +} + +fn test_return_expr() -> i32 { + let a: i32 = 10; + //~^ needless_type_cast + a as i32 +} + +fn test_closure_always_cast() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a as i32; +} + +fn test_closure_mixed_usage() { + let a: u8 = 10; + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a + 1; +} + +fn test_nested_generic_call() { + let a: u8 = 10; + let _ = generic(takes_i32(a as i32)); + let _ = generic(takes_i32(a as i32)); +} + +fn test_generic_initializer() { + // Should not lint: changing type would affect what generic() returns + let a: u8 = generic(10u8); + let _ = a as i32; + let _ = a as i32; +} + +fn test_unsafe_transmute() { + // Should not lint: initializer contains unsafe block + #[allow(clippy::useless_transmute)] + let x: u32 = unsafe { std::mem::transmute(0u32) }; + let _ = x as u64; +} + +fn test_if_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = if true { generic(1) } else { 2 }; + let _ = x as i32; +} + +fn test_match_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = match 1 { + 1 => generic(1), + _ => 2, + }; + let _ = x as i32; +} + +fn test_default() { + // Should not lint: Default::default() has generic return type + let x: u8 = Default::default(); + let _ = x as i32; +} + +fn test_loop_with_generic() { + // Should not lint: loop break has generic return type + #[allow(clippy::never_loop)] + let x: u8 = loop { + break generic(1); + }; + let _ = x as i32; +} diff --git a/src/tools/clippy/tests/ui/needless_type_cast.rs b/src/tools/clippy/tests/ui/needless_type_cast.rs new file mode 100644 index 0000000000000..e28f620e035f6 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_type_cast.rs @@ -0,0 +1,182 @@ +#![warn(clippy::needless_type_cast)] +#![allow(clippy::no_effect, clippy::unnecessary_cast, unused)] + +fn takes_i32(x: i32) -> i32 { + x +} + +fn generic(x: T) -> T { + x +} + +fn main() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = a as i32 + 5; + let _ = a as i32 * 2; + + let b: u16 = 20; + let _ = b; + let _ = b as u32; + + let c: u8 = 5; + let _ = c as u16; + let _ = c as u32; + + let d: i32 = 100; + let _ = d + 1; + + let e = 42u8; + let _ = e as i64; + let _ = e as i64 + 10; + + let f: u8 = 1; + //~^ needless_type_cast + let _ = f as usize; +} + +fn test_function_call() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = takes_i32(a as i32); + let _ = takes_i32(a as i32); +} + +fn test_generic_call() { + let a: u8 = 10; + let _ = generic(a as i32); + let _ = generic(a as i32); +} + +fn test_method_on_cast() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = (a as i32).checked_add(5); + let _ = (a as i32).saturating_mul(2); +} + +fn test_iterator_sum() { + let a: u8 = 10; + //~^ needless_type_cast + let arr = [a as i32, a as i32]; + let _: i32 = arr.iter().copied().sum(); +} + +fn test_closure() { + let a: u8 = 10; + //~^ needless_type_cast + let _: i32 = [1i32, 2].iter().map(|x| x + a as i32).sum(); +} + +fn test_struct_field() { + struct S { + x: i32, + y: i32, + } + + let a: u8 = 10; + //~^ needless_type_cast + let _ = S { + x: a as i32, + y: a as i32, + }; +} + +fn test_option() { + let a: u8 = 10; + let _: Option = Some(a as i32); + let _: Option = Some(a as i32); +} + +fn test_mixed_context() { + let a: u8 = 10; + let _ = takes_i32(a as i32); + let _ = generic(a as i32); +} + +fn test_nested_block() { + if true { + let a: u8 = 10; + //~^ needless_type_cast + let _ = a as i32 + 1; + let _ = a as i32 * 2; + } +} + +fn test_match_expr() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = match 1 { + 1 => a as i32, + _ => a as i32, + }; +} + +fn test_return_expr() -> i32 { + let a: u8 = 10; + //~^ needless_type_cast + a as i32 +} + +fn test_closure_always_cast() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a as i32; +} + +fn test_closure_mixed_usage() { + let a: u8 = 10; + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a + 1; +} + +fn test_nested_generic_call() { + let a: u8 = 10; + let _ = generic(takes_i32(a as i32)); + let _ = generic(takes_i32(a as i32)); +} + +fn test_generic_initializer() { + // Should not lint: changing type would affect what generic() returns + let a: u8 = generic(10u8); + let _ = a as i32; + let _ = a as i32; +} + +fn test_unsafe_transmute() { + // Should not lint: initializer contains unsafe block + #[allow(clippy::useless_transmute)] + let x: u32 = unsafe { std::mem::transmute(0u32) }; + let _ = x as u64; +} + +fn test_if_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = if true { generic(1) } else { 2 }; + let _ = x as i32; +} + +fn test_match_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = match 1 { + 1 => generic(1), + _ => 2, + }; + let _ = x as i32; +} + +fn test_default() { + // Should not lint: Default::default() has generic return type + let x: u8 = Default::default(); + let _ = x as i32; +} + +fn test_loop_with_generic() { + // Should not lint: loop break has generic return type + #[allow(clippy::never_loop)] + let x: u8 = loop { + break generic(1); + }; + let _ = x as i32; +} diff --git a/src/tools/clippy/tests/ui/needless_type_cast.stderr b/src/tools/clippy/tests/ui/needless_type_cast.stderr new file mode 100644 index 0000000000000..3ee9df1043e74 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_type_cast.stderr @@ -0,0 +1,71 @@ +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:13:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + | + = note: `-D clippy::needless-type-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_type_cast)]` + +error: this binding is defined as `u8` but is always cast to `usize` + --> tests/ui/needless_type_cast.rs:33:12 + | +LL | let f: u8 = 1; + | ^^ help: consider defining it as: `usize` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:39:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:52:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:59:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:66:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:77:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:99:16 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:107:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:116:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:122:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: aborting due to 11 previous errors + diff --git a/src/tools/clippy/tests/ui/ptr_offset_by_literal.fixed b/src/tools/clippy/tests/ui/ptr_offset_by_literal.fixed new file mode 100644 index 0000000000000..bd9e41def938d --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_offset_by_literal.fixed @@ -0,0 +1,50 @@ +#![warn(clippy::ptr_offset_by_literal)] +#![allow(clippy::inconsistent_digit_grouping)] + +fn main() { + let arr = [b'a', b'b', b'c']; + let ptr = arr.as_ptr(); + + let var = 32; + const CONST: isize = 42; + + unsafe { + let _ = ptr; + //~^ ptr_offset_by_literal + let _ = ptr; + //~^ ptr_offset_by_literal + + let _ = ptr.add(5); + //~^ ptr_offset_by_literal + let _ = ptr.sub(5); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(var); + let _ = ptr.offset(CONST); + + let _ = ptr.wrapping_add(5); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_sub(5); + //~^ ptr_offset_by_literal + + let _ = ptr.sub(5); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_sub(5); + //~^ ptr_offset_by_literal + + // isize::MAX and isize::MIN on 32-bit systems. + let _ = ptr.add(2_147_483_647); + //~^ ptr_offset_by_literal + let _ = ptr.sub(2_147_483_648); + //~^ ptr_offset_by_literal + + let _ = ptr.add(5_0); + //~^ ptr_offset_by_literal + let _ = ptr.sub(5_0); + //~^ ptr_offset_by_literal + + macro_rules! offs { { $e:expr, $offs:expr } => { $e.offset($offs) }; } + offs!(ptr, 6); + offs!(ptr, var); + } +} diff --git a/src/tools/clippy/tests/ui/ptr_offset_by_literal.rs b/src/tools/clippy/tests/ui/ptr_offset_by_literal.rs new file mode 100644 index 0000000000000..b8e3f9b26c68f --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_offset_by_literal.rs @@ -0,0 +1,50 @@ +#![warn(clippy::ptr_offset_by_literal)] +#![allow(clippy::inconsistent_digit_grouping)] + +fn main() { + let arr = [b'a', b'b', b'c']; + let ptr = arr.as_ptr(); + + let var = 32; + const CONST: isize = 42; + + unsafe { + let _ = ptr.offset(0); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-0); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(5); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-5); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(var); + let _ = ptr.offset(CONST); + + let _ = ptr.wrapping_offset(5isize); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_offset(-5isize); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(-(5)); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_offset(-(5)); + //~^ ptr_offset_by_literal + + // isize::MAX and isize::MIN on 32-bit systems. + let _ = ptr.offset(2_147_483_647isize); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-2_147_483_648isize); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(5_0__isize); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-5_0__isize); + //~^ ptr_offset_by_literal + + macro_rules! offs { { $e:expr, $offs:expr } => { $e.offset($offs) }; } + offs!(ptr, 6); + offs!(ptr, var); + } +} diff --git a/src/tools/clippy/tests/ui/ptr_offset_by_literal.stderr b/src/tools/clippy/tests/ui/ptr_offset_by_literal.stderr new file mode 100644 index 0000000000000..f85fef87d55f2 --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_offset_by_literal.stderr @@ -0,0 +1,141 @@ +error: use of `offset` with zero + --> tests/ui/ptr_offset_by_literal.rs:12:17 + | +LL | let _ = ptr.offset(0); + | ^^^---------- + | | + | help: remove the call to `offset` + | + = note: `-D clippy::ptr-offset-by-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_offset_by_literal)]` + +error: use of `offset` with zero + --> tests/ui/ptr_offset_by_literal.rs:14:17 + | +LL | let _ = ptr.offset(-0); + | ^^^----------- + | | + | help: remove the call to `offset` + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:17:17 + | +LL | let _ = ptr.offset(5); + | ^^^^^^^^^^^^^ + | +help: use `add` instead + | +LL - let _ = ptr.offset(5); +LL + let _ = ptr.add(5); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:19:17 + | +LL | let _ = ptr.offset(-5); + | ^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-5); +LL + let _ = ptr.sub(5); + | + +error: use of `wrapping_offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:25:17 + | +LL | let _ = ptr.wrapping_offset(5isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `wrapping_add` instead + | +LL - let _ = ptr.wrapping_offset(5isize); +LL + let _ = ptr.wrapping_add(5); + | + +error: use of `wrapping_offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:27:17 + | +LL | let _ = ptr.wrapping_offset(-5isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `wrapping_sub` instead + | +LL - let _ = ptr.wrapping_offset(-5isize); +LL + let _ = ptr.wrapping_sub(5); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:30:17 + | +LL | let _ = ptr.offset(-(5)); + | ^^^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-(5)); +LL + let _ = ptr.sub(5); + | + +error: use of `wrapping_offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:32:17 + | +LL | let _ = ptr.wrapping_offset(-(5)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `wrapping_sub` instead + | +LL - let _ = ptr.wrapping_offset(-(5)); +LL + let _ = ptr.wrapping_sub(5); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:36:17 + | +LL | let _ = ptr.offset(2_147_483_647isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `add` instead + | +LL - let _ = ptr.offset(2_147_483_647isize); +LL + let _ = ptr.add(2_147_483_647); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:38:17 + | +LL | let _ = ptr.offset(-2_147_483_648isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-2_147_483_648isize); +LL + let _ = ptr.sub(2_147_483_648); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:41:17 + | +LL | let _ = ptr.offset(5_0__isize); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `add` instead + | +LL - let _ = ptr.offset(5_0__isize); +LL + let _ = ptr.add(5_0); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:43:17 + | +LL | let _ = ptr.offset(-5_0__isize); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-5_0__isize); +LL + let _ = ptr.sub(5_0); + | + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed index 1213fdcf61197..daae41c0c891b 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed @@ -311,19 +311,23 @@ mod issue9120 { } } +// skip this test due to rust-lang/rust-clippy#16086 +/* #[allow(clippy::match_like_matches_macro)] fn issue15102() { let values = [None, Some(3)]; - let has_even = values.iter().any(|v| matches!(&v, Some(x) if x % 2 == 0)); - //~^ search_is_some + let has_even = values.iter().find(|v| matches!(v, Some(x) if x % 2 == 0)).is_some(); + ~^ search_is_some println!("{has_even}"); let has_even = values .iter() - .any(|v| match &v { - //~^ search_is_some + .find(|v| match v { + ~^ search_is_some Some(x) if x % 2 == 0 => true, _ => false, - }); + }) + .is_some(); println!("{has_even}"); } +*/ diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs index 4294a39333f20..ead101a491a6a 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs @@ -322,20 +322,23 @@ mod issue9120 { } } +// skip this test due to rust-lang/rust-clippy#16086 +/* #[allow(clippy::match_like_matches_macro)] fn issue15102() { let values = [None, Some(3)]; let has_even = values.iter().find(|v| matches!(v, Some(x) if x % 2 == 0)).is_some(); - //~^ search_is_some + ~^ search_is_some println!("{has_even}"); let has_even = values .iter() .find(|v| match v { - //~^ search_is_some + ~^ search_is_some Some(x) if x % 2 == 0 => true, _ => false, }) .is_some(); println!("{has_even}"); } +*/ diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr index cee1eb08876ba..c56fe859aac09 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr @@ -346,32 +346,5 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| (*arg_no_deref_dyn)(&x))` -error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:328:34 - | -LL | let has_even = values.iter().find(|v| matches!(v, Some(x) if x % 2 == 0)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| matches!(&v, Some(x) if x % 2 == 0))` - -error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:334:10 - | -LL | .find(|v| match v { - | __________^ -LL | | -LL | | Some(x) if x % 2 == 0 => true, -LL | | _ => false, -LL | | }) -LL | | .is_some(); - | |__________________^ - | -help: consider using - | -LL ~ .any(|v| match &v { -LL + -LL + Some(x) if x % 2 == 0 => true, -LL + _ => false, -LL ~ }); - | - -error: aborting due to 51 previous errors +error: aborting due to 49 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed index 476e7e35a1f61..caba277db754d 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed @@ -24,6 +24,13 @@ struct GenericParam { t: T, } +#[derive(Clone, Copy)] +struct PtrNamed { + ptr: *const u32, +} +#[derive(Clone, Copy)] +struct Ptr(*const u32); + fn transmute_ptr_to_ptr() { let ptr = &1u32 as *const u32; let mut_ptr = &mut 1u32 as *mut u32; @@ -68,6 +75,18 @@ fn transmute_ptr_to_ptr() { let _: &GenericParam<&LifetimeParam<'static>> = unsafe { transmute(&GenericParam { t: &lp }) }; } +fn issue1966() { + let ptr = &1u32 as *const u32; + unsafe { + let _: *const f32 = Ptr(ptr).0.cast::(); + //~^ transmute_ptr_to_ptr + let _: *const f32 = PtrNamed { ptr }.ptr.cast::(); + //~^ transmute_ptr_to_ptr + let _: *mut u32 = Ptr(ptr).0.cast_mut(); + //~^ transmute_ptr_to_ptr + } +} + fn lifetime_to_static(v: *mut &()) -> *const &'static () { unsafe { v as *const &() } //~^ transmute_ptr_to_ptr @@ -81,11 +100,15 @@ const _: &() = { unsafe { transmute::<&'static Zst, &'static ()>(zst) } }; +#[derive(Clone, Copy)] +struct Ptr8(*const u8); #[clippy::msrv = "1.37"] fn msrv_1_37(ptr: *const u8) { unsafe { let _: *const i8 = ptr as *const i8; //~^ transmute_ptr_to_ptr + let _: *const i8 = Ptr8(ptr).0 as *const i8; + //~^ transmute_ptr_to_ptr } } diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs index 7356668bcab5a..b3c2baf29c361 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs @@ -24,6 +24,13 @@ struct GenericParam { t: T, } +#[derive(Clone, Copy)] +struct PtrNamed { + ptr: *const u32, +} +#[derive(Clone, Copy)] +struct Ptr(*const u32); + fn transmute_ptr_to_ptr() { let ptr = &1u32 as *const u32; let mut_ptr = &mut 1u32 as *mut u32; @@ -68,6 +75,18 @@ fn transmute_ptr_to_ptr() { let _: &GenericParam<&LifetimeParam<'static>> = unsafe { transmute(&GenericParam { t: &lp }) }; } +fn issue1966() { + let ptr = &1u32 as *const u32; + unsafe { + let _: *const f32 = transmute(Ptr(ptr)); + //~^ transmute_ptr_to_ptr + let _: *const f32 = transmute(PtrNamed { ptr }); + //~^ transmute_ptr_to_ptr + let _: *mut u32 = transmute(Ptr(ptr)); + //~^ transmute_ptr_to_ptr + } +} + fn lifetime_to_static(v: *mut &()) -> *const &'static () { unsafe { transmute(v) } //~^ transmute_ptr_to_ptr @@ -81,11 +100,15 @@ const _: &() = { unsafe { transmute::<&'static Zst, &'static ()>(zst) } }; +#[derive(Clone, Copy)] +struct Ptr8(*const u8); #[clippy::msrv = "1.37"] fn msrv_1_37(ptr: *const u8) { unsafe { let _: *const i8 = transmute(ptr); //~^ transmute_ptr_to_ptr + let _: *const i8 = transmute(Ptr8(ptr)); + //~^ transmute_ptr_to_ptr } } diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr index c8db4fe214fdb..ba9e6df6c2d7c 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr @@ -1,5 +1,5 @@ error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:32:29 + --> tests/ui/transmute_ptr_to_ptr.rs:39:29 | LL | let _: *const f32 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + let _: *const f32 = ptr.cast::(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:35:27 + --> tests/ui/transmute_ptr_to_ptr.rs:42:27 | LL | let _: *mut f32 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -25,37 +25,37 @@ LL + let _: *mut f32 = mut_ptr.cast::(); | error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:39:23 + --> tests/ui/transmute_ptr_to_ptr.rs:46:23 | LL | let _: &f32 = transmute(&1u32); | ^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:42:23 + --> tests/ui/transmute_ptr_to_ptr.rs:49:23 | LL | let _: &f32 = transmute(&1f64); | ^^^^^^^^^^^^^^^^ help: try: `&*(&1f64 as *const f64 as *const f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:47:27 + --> tests/ui/transmute_ptr_to_ptr.rs:54:27 | LL | let _: &mut f32 = transmute(&mut 1u32); | ^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:50:37 + --> tests/ui/transmute_ptr_to_ptr.rs:57:37 | LL | let _: &GenericParam = transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:54:27 + --> tests/ui/transmute_ptr_to_ptr.rs:61:27 | LL | let u8_ref: &u8 = transmute(u64_ref); | ^^^^^^^^^^^^^^^^^^ help: try: `&*(u64_ref as *const u64 as *const u8)` error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:57:29 + --> tests/ui/transmute_ptr_to_ptr.rs:64:29 | LL | let _: *const u32 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL + let _: *const u32 = mut_ptr.cast_const(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:60:27 + --> tests/ui/transmute_ptr_to_ptr.rs:67:27 | LL | let _: *mut u32 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -79,7 +79,43 @@ LL + let _: *mut u32 = ptr.cast_mut(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:72:14 + --> tests/ui/transmute_ptr_to_ptr.rs:81:29 + | +LL | let _: *const f32 = transmute(Ptr(ptr)); + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast` instead + | +LL - let _: *const f32 = transmute(Ptr(ptr)); +LL + let _: *const f32 = Ptr(ptr).0.cast::(); + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:83:29 + | +LL | let _: *const f32 = transmute(PtrNamed { ptr }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast` instead + | +LL - let _: *const f32 = transmute(PtrNamed { ptr }); +LL + let _: *const f32 = PtrNamed { ptr }.ptr.cast::(); + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:85:27 + | +LL | let _: *mut u32 = transmute(Ptr(ptr)); + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast_mut` instead + | +LL - let _: *mut u32 = transmute(Ptr(ptr)); +LL + let _: *mut u32 = Ptr(ptr).0.cast_mut(); + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:91:14 | LL | unsafe { transmute(v) } | ^^^^^^^^^^^^ @@ -91,7 +127,7 @@ LL + unsafe { v as *const &() } | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:87:28 + --> tests/ui/transmute_ptr_to_ptr.rs:108:28 | LL | let _: *const i8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -103,7 +139,19 @@ LL + let _: *const i8 = ptr as *const i8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:95:28 + --> tests/ui/transmute_ptr_to_ptr.rs:110:28 + | +LL | let _: *const i8 = transmute(Ptr8(ptr)); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use an `as` cast instead + | +LL - let _: *const i8 = transmute(Ptr8(ptr)); +LL + let _: *const i8 = Ptr8(ptr).0 as *const i8; + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:118:28 | LL | let _: *const i8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -115,7 +163,7 @@ LL + let _: *const i8 = ptr.cast::(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:103:26 + --> tests/ui/transmute_ptr_to_ptr.rs:126:26 | LL | let _: *mut u8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -127,7 +175,7 @@ LL + let _: *mut u8 = ptr as *mut u8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:105:28 + --> tests/ui/transmute_ptr_to_ptr.rs:128:28 | LL | let _: *const u8 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -139,7 +187,7 @@ LL + let _: *const u8 = mut_ptr as *const u8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:113:26 + --> tests/ui/transmute_ptr_to_ptr.rs:136:26 | LL | let _: *mut u8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -151,7 +199,7 @@ LL + let _: *mut u8 = ptr.cast_mut(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:115:28 + --> tests/ui/transmute_ptr_to_ptr.rs:138:28 | LL | let _: *const u8 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -162,5 +210,5 @@ LL - let _: *const u8 = transmute(mut_ptr); LL + let _: *const u8 = mut_ptr.cast_const(); | -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed index c130575df9607..8de47031a4009 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed @@ -55,6 +55,52 @@ fn issue1231() { //~^ transmute_ptr_to_ref } +#[derive(Clone, Copy)] +struct PtrRefNamed<'a> { + ptr: *const &'a u32, +} +#[derive(Clone, Copy)] +struct PtrRef<'a>(*const &'a u32); +#[derive(Clone, Copy)] +struct PtrSliceRef<'a>(*const [&'a str]); +#[derive(Clone, Copy)] +struct PtrSlice(*const [i32]); +#[derive(Clone, Copy)] +struct Ptr(*const u32); +impl std::ops::Add for Ptr { + type Output = Self; + fn add(self, _: Self) -> Self { + self + } +} +mod ptr_mod { + #[derive(Clone, Copy)] + pub struct Ptr(*const u32); +} +fn issue1966(u: PtrSlice, v: PtrSliceRef, w: Ptr, x: PtrRefNamed, y: PtrRef, z: ptr_mod::Ptr) { + unsafe { + let _: &i32 = &*(w.0 as *const i32); + //~^ transmute_ptr_to_ref + let _: &u32 = &*w.0; + //~^ transmute_ptr_to_ref + let _: &&u32 = &*x.ptr.cast::<&u32>(); + //~^ transmute_ptr_to_ref + // The field is not accessible. The program should not generate code + // that accesses the field. + let _: &u32 = std::mem::transmute(z); + let _ = &*w.0.cast::(); + //~^ transmute_ptr_to_ref + let _: &[&str] = &*(v.0 as *const [&str]); + //~^ transmute_ptr_to_ref + let _ = &*(u.0 as *const [i32]); + //~^ transmute_ptr_to_ref + let _: &&u32 = &*y.0.cast::<&u32>(); + //~^ transmute_ptr_to_ref + let _: &u32 = &*(w + w).0; + //~^ transmute_ptr_to_ref + } +} + fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { unsafe { match 0 { @@ -89,7 +135,7 @@ fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { } #[clippy::msrv = "1.37"] -fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { +fn under_msrv<'a, 'b, 'c>(x: *const &'a u32, y: PtrRef) -> &'c &'b u32 { unsafe { let a = 0u32; let a = &a as *const u32; @@ -97,10 +143,16 @@ fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { //~^ transmute_ptr_to_ref let _: &u32 = &*(a as *const u32); //~^ transmute_ptr_to_ref + let _ = &*(Ptr(a).0 as *const u32); + //~^ transmute_ptr_to_ref match 0 { 0 => &*(x as *const () as *const &u32), //~^ transmute_ptr_to_ref - _ => &*(x as *const () as *const &'b u32), + 1 => &*(x as *const () as *const &'b u32), + //~^ transmute_ptr_to_ref + 2 => &*(y.0 as *const () as *const &u32), + //~^ transmute_ptr_to_ref + _ => &*(y.0 as *const () as *const &'b u32), //~^ transmute_ptr_to_ref } } diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs index f79d54234a2c9..52fe669de9355 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs @@ -55,6 +55,52 @@ fn issue1231() { //~^ transmute_ptr_to_ref } +#[derive(Clone, Copy)] +struct PtrRefNamed<'a> { + ptr: *const &'a u32, +} +#[derive(Clone, Copy)] +struct PtrRef<'a>(*const &'a u32); +#[derive(Clone, Copy)] +struct PtrSliceRef<'a>(*const [&'a str]); +#[derive(Clone, Copy)] +struct PtrSlice(*const [i32]); +#[derive(Clone, Copy)] +struct Ptr(*const u32); +impl std::ops::Add for Ptr { + type Output = Self; + fn add(self, _: Self) -> Self { + self + } +} +mod ptr_mod { + #[derive(Clone, Copy)] + pub struct Ptr(*const u32); +} +fn issue1966(u: PtrSlice, v: PtrSliceRef, w: Ptr, x: PtrRefNamed, y: PtrRef, z: ptr_mod::Ptr) { + unsafe { + let _: &i32 = std::mem::transmute(w); + //~^ transmute_ptr_to_ref + let _: &u32 = std::mem::transmute(w); + //~^ transmute_ptr_to_ref + let _: &&u32 = core::mem::transmute(x); + //~^ transmute_ptr_to_ref + // The field is not accessible. The program should not generate code + // that accesses the field. + let _: &u32 = std::mem::transmute(z); + let _ = std::mem::transmute::<_, &u32>(w); + //~^ transmute_ptr_to_ref + let _: &[&str] = core::mem::transmute(v); + //~^ transmute_ptr_to_ref + let _ = std::mem::transmute::<_, &[i32]>(u); + //~^ transmute_ptr_to_ref + let _: &&u32 = std::mem::transmute(y); + //~^ transmute_ptr_to_ref + let _: &u32 = std::mem::transmute(w + w); + //~^ transmute_ptr_to_ref + } +} + fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { unsafe { match 0 { @@ -89,7 +135,7 @@ fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { } #[clippy::msrv = "1.37"] -fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { +fn under_msrv<'a, 'b, 'c>(x: *const &'a u32, y: PtrRef) -> &'c &'b u32 { unsafe { let a = 0u32; let a = &a as *const u32; @@ -97,10 +143,16 @@ fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { //~^ transmute_ptr_to_ref let _: &u32 = std::mem::transmute::<_, &u32>(a); //~^ transmute_ptr_to_ref + let _ = std::mem::transmute::<_, &u32>(Ptr(a)); + //~^ transmute_ptr_to_ref match 0 { 0 => std::mem::transmute(x), //~^ transmute_ptr_to_ref - _ => std::mem::transmute::<_, &&'b u32>(x), + 1 => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref + 2 => std::mem::transmute(y), + //~^ transmute_ptr_to_ref + _ => std::mem::transmute::<_, &&'b u32>(y), //~^ transmute_ptr_to_ref } } diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr index 3f404d295fef0..c0f0ca916761d 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr @@ -61,125 +61,191 @@ error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` +error: transmute from a pointer type (`*const u32`) to a reference type (`&i32`) + --> tests/ui/transmute_ptr_to_ref.rs:82:23 + | +LL | let _: &i32 = std::mem::transmute(w); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(w.0 as *const i32)` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:84:23 + | +LL | let _: &u32 = std::mem::transmute(w); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*w.0` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:86:24 + | +LL | let _: &&u32 = core::mem::transmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.ptr.cast::<&u32>()` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:91:17 + | +LL | let _ = std::mem::transmute::<_, &u32>(w); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*w.0.cast::()` + +error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`) + --> tests/ui/transmute_ptr_to_ref.rs:93:26 + | +LL | let _: &[&str] = core::mem::transmute(v); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(v.0 as *const [&str])` + +error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`) + --> tests/ui/transmute_ptr_to_ref.rs:95:17 + | +LL | let _ = std::mem::transmute::<_, &[i32]>(u); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(u.0 as *const [i32])` + error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:61:18 + --> tests/ui/transmute_ptr_to_ref.rs:97:24 + | +LL | let _: &&u32 = std::mem::transmute(y); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.0.cast::<&u32>()` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:99:23 + | +LL | let _: &u32 = std::mem::transmute(w + w); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(w + w).0` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:107:18 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:63:18 + --> tests/ui/transmute_ptr_to_ref.rs:109:18 | LL | 1 => std::mem::transmute(y), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:65:18 + --> tests/ui/transmute_ptr_to_ref.rs:111:18 | LL | 2 => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:67:18 + --> tests/ui/transmute_ptr_to_ref.rs:113:18 | LL | _ => std::mem::transmute::<_, &&'b u32>(y), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:78:23 + --> tests/ui/transmute_ptr_to_ref.rs:124:23 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:80:23 + --> tests/ui/transmute_ptr_to_ref.rs:126:23 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:83:18 + --> tests/ui/transmute_ptr_to_ref.rs:129:18 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:85:18 + --> tests/ui/transmute_ptr_to_ref.rs:131:18 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:96:23 + --> tests/ui/transmute_ptr_to_ref.rs:142:23 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:98:23 + --> tests/ui/transmute_ptr_to_ref.rs:144:23 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:146:17 + | +LL | let _ = std::mem::transmute::<_, &u32>(Ptr(a)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(Ptr(a).0 as *const u32)` + error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:101:18 + --> tests/ui/transmute_ptr_to_ref.rs:149:18 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:103:18 + --> tests/ui/transmute_ptr_to_ref.rs:151:18 | -LL | _ => std::mem::transmute::<_, &&'b u32>(x), +LL | 1 => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:153:18 + | +LL | 2 => std::mem::transmute(y), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(y.0 as *const () as *const &u32)` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:155:18 + | +LL | _ => std::mem::transmute::<_, &&'b u32>(y), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(y.0 as *const () as *const &'b u32)` + error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`) - --> tests/ui/transmute_ptr_to_ref.rs:113:17 + --> tests/ui/transmute_ptr_to_ref.rs:165:17 | LL | let _ = core::mem::transmute::<_, &[u32]>(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])` error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`) - --> tests/ui/transmute_ptr_to_ref.rs:115:25 + --> tests/ui/transmute_ptr_to_ref.rs:167:25 | LL | let _: &[u32] = core::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`) - --> tests/ui/transmute_ptr_to_ref.rs:119:17 + --> tests/ui/transmute_ptr_to_ref.rs:171:17 | LL | let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`) - --> tests/ui/transmute_ptr_to_ref.rs:121:27 + --> tests/ui/transmute_ptr_to_ref.rs:173:27 | LL | let _: &[&[u8]] = core::mem::transmute(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])` error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`) - --> tests/ui/transmute_ptr_to_ref.rs:125:17 + --> tests/ui/transmute_ptr_to_ref.rs:177:17 | LL | let _ = core::mem::transmute::<_, &[i32]>(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [i32])` error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`) - --> tests/ui/transmute_ptr_to_ref.rs:127:25 + --> tests/ui/transmute_ptr_to_ref.rs:179:25 | LL | let _: &[i32] = core::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*ptr` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`) - --> tests/ui/transmute_ptr_to_ref.rs:131:17 + --> tests/ui/transmute_ptr_to_ref.rs:183:17 | LL | let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`) - --> tests/ui/transmute_ptr_to_ref.rs:133:26 + --> tests/ui/transmute_ptr_to_ref.rs:185:26 | LL | let _: &[&str] = core::mem::transmute(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])` -error: aborting due to 30 previous errors +error: aborting due to 41 previous errors diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.rs b/src/tools/clippy/tests/ui/tuple_array_conversions.rs index 772c41df090e5..17e6a252b2669 100644 --- a/src/tools/clippy/tests/ui/tuple_array_conversions.rs +++ b/src/tools/clippy/tests/ui/tuple_array_conversions.rs @@ -116,3 +116,26 @@ fn msrv_juust_right() { let x = &[1, 2]; let x = (x[0], x[1]); } + +fn issue16192() { + fn do_something(tuple: (u32, u32)) {} + fn produce_array() -> [u32; 2] { + [1, 2] + } + + let [a, b] = produce_array(); + for tuple in [(a, b), (b, a)] { + do_something(tuple); + } + + let [a, b] = produce_array(); + let x = b; + do_something((a, b)); + + let [a, b] = produce_array(); + do_something((b, a)); + + let [a, b] = produce_array(); + do_something((a, b)); + //~^ tuple_array_conversions +} diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr index 6dafb8d285d4d..4c15769b74875 100644 --- a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr +++ b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr @@ -80,5 +80,13 @@ LL | let x = [x.0, x.1]; | = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed -error: aborting due to 10 previous errors +error: it looks like you're trying to convert an array to a tuple + --> tests/ui/tuple_array_conversions.rs:139:18 + | +LL | do_something((a, b)); + | ^^^^^^ + | + = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 9de7d2c67149d..adf5e58d9a1ab 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -442,3 +442,14 @@ fn issue14739() { let _ = R.map(|_x| 0); //~^ useless_conversion } + +fn issue16165() { + macro_rules! mac { + (iter $e:expr) => { + $e.iter() + }; + } + + for _ in mac!(iter [1, 2]) {} + //~^ useless_conversion +} diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 38cd1175aa485..d95fe49e2e2be 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -442,3 +442,14 @@ fn issue14739() { let _ = R.into_iter().map(|_x| 0); //~^ useless_conversion } + +fn issue16165() { + macro_rules! mac { + (iter $e:expr) => { + $e.iter() + }; + } + + for _ in mac!(iter [1, 2]).into_iter() {} + //~^ useless_conversion +} diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index 3bfaf1411c2c6..052c664f6f2e1 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -389,5 +389,11 @@ error: useless conversion to the same type: `std::ops::Range` LL | let _ = R.into_iter().map(|_x| 0); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` -error: aborting due to 43 previous errors +error: useless conversion to the same type: `std::slice::Iter<'_, i32>` + --> tests/ui/useless_conversion.rs:453:14 + | +LL | for _ in mac!(iter [1, 2]).into_iter() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `mac!(iter [1, 2])` + +error: aborting due to 44 previous errors diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed index f9ccefab5898d..0d3b446af43fa 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed @@ -492,6 +492,110 @@ fn issue13123() { } } +fn issue16089() { + trait CertainTrait: Iterator { + fn iter_over_self(&mut self) { + let mut a = 0; + for r in &mut *self { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + +fn issue16089_sized_trait_not_reborrowed() { + trait CertainTrait: Iterator + Sized { + fn iter_over_self(&mut self) { + let mut a = 0; + // Check that the suggestion is just "self", since the trait is sized. + for r in self.by_ref() { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + +fn issue16089_nested_derefs() { + struct S(T); + impl core::ops::Deref for S { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for S { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + fn f(mut x: S>>) { + for _ in &mut ***x {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_not_sized() { + struct WithSize(T); + impl core::ops::Deref for WithSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for WithSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + // The suggestion must use `&mut **x`. Using `x.by_ref()` doesn't work in this + // case, since the last type adjustment for `x` in the expression `x.next()` is + // to dereference a `?Sized` trait. + fn f(mut x: WithSize<&mut dyn Iterator>) { + for _ in &mut **x {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_sized() { + struct NoSize(T); + impl core::ops::Deref for NoSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for NoSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct SizedIter {} + + impl Iterator for SizedIter { + type Item = u32; + fn next(&mut self) -> Option { + Some(0) + } + } + + // We want the suggestion to be `x.by_ref()`. It works in this case since the last type + // adjustment for `x` in the expression `x.next()` is to dereference a Sized type. + fn f(mut x: NoSize>) { + for _ in x.by_ref() {} + //~^ while_let_on_iterator + } +} + fn main() { let mut it = 0..20; for _ in it { diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs index f957f2e5a5238..e1d9e9081e452 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs @@ -492,6 +492,110 @@ fn issue13123() { } } +fn issue16089() { + trait CertainTrait: Iterator { + fn iter_over_self(&mut self) { + let mut a = 0; + while let Some(r) = self.next() { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + +fn issue16089_sized_trait_not_reborrowed() { + trait CertainTrait: Iterator + Sized { + fn iter_over_self(&mut self) { + let mut a = 0; + // Check that the suggestion is just "self", since the trait is sized. + while let Some(r) = self.next() { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + +fn issue16089_nested_derefs() { + struct S(T); + impl core::ops::Deref for S { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for S { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + fn f(mut x: S>>) { + while let Some(_) = x.next() {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_not_sized() { + struct WithSize(T); + impl core::ops::Deref for WithSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for WithSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + // The suggestion must use `&mut **x`. Using `x.by_ref()` doesn't work in this + // case, since the last type adjustment for `x` in the expression `x.next()` is + // to dereference a `?Sized` trait. + fn f(mut x: WithSize<&mut dyn Iterator>) { + while let Some(_) = x.next() {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_sized() { + struct NoSize(T); + impl core::ops::Deref for NoSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for NoSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct SizedIter {} + + impl Iterator for SizedIter { + type Item = u32; + fn next(&mut self) -> Option { + Some(0) + } + } + + // We want the suggestion to be `x.by_ref()`. It works in this case since the last type + // adjustment for `x` in the expression `x.next()` is to dereference a Sized type. + fn f(mut x: NoSize>) { + while let Some(_) = x.next() {} + //~^ while_let_on_iterator + } +} + fn main() { let mut it = 0..20; while let Some(..) = it.next() { diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr index 50f20227b90f9..cd43d3c17800e 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr @@ -164,10 +164,40 @@ LL | 'label: while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'label: for n in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:497:5 + --> tests/ui/while_let_on_iterator.rs:499:13 + | +LL | while let Some(r) = self.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for r in &mut *self` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:515:13 + | +LL | while let Some(r) = self.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for r in self.by_ref()` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:541:9 + | +LL | while let Some(_) = x.next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in &mut ***x` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:563:9 + | +LL | while let Some(_) = x.next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in &mut **x` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:594:9 + | +LL | while let Some(_) = x.next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in x.by_ref()` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:601:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` -error: aborting due to 28 previous errors +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/zero_offset.rs b/src/tools/clippy/tests/ui/zero_offset.rs index bedb09536c538..5a9c3ac9248fa 100644 --- a/src/tools/clippy/tests/ui/zero_offset.rs +++ b/src/tools/clippy/tests/ui/zero_offset.rs @@ -1,4 +1,4 @@ -#[allow(clippy::borrow_as_ptr)] +#[allow(clippy::borrow_as_ptr, clippy::ptr_offset_by_literal)] fn main() { unsafe { let m = &mut () as *mut (); diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed index b5fca36f3f089..4bdff6fd0f6c5 100644 --- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed +++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed @@ -1,6 +1,11 @@ #![warn(clippy::zero_repeat_side_effects)] -#![expect(clippy::unnecessary_operation, clippy::useless_vec, clippy::needless_late_init)] -#![allow(clippy::no_effect)] // only fires _after_ the fix +#![allow( + clippy::unnecessary_operation, + clippy::useless_vec, + clippy::needless_late_init, + clippy::single_match, + clippy::no_effect // only fires _after_ the fix +)] fn f() -> i32 { println!("side effect"); @@ -119,3 +124,26 @@ fn issue_14681() { }); //~^ zero_repeat_side_effects } + +fn issue_15824() { + fn f() {} + + match 0 { + 0 => { + f(); + _ = [] as [(); 0] + }, + //~^ zero_repeat_side_effects + _ => {}, + } + + let mut a = [(); 0]; + match 0 { + 0 => { + f(); + a = [] as [(); 0] + }, + //~^ zero_repeat_side_effects + _ => {}, + } +} diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs index ea043d21638cc..a1454d724c870 100644 --- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs +++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs @@ -1,6 +1,11 @@ #![warn(clippy::zero_repeat_side_effects)] -#![expect(clippy::unnecessary_operation, clippy::useless_vec, clippy::needless_late_init)] -#![allow(clippy::no_effect)] // only fires _after_ the fix +#![allow( + clippy::unnecessary_operation, + clippy::useless_vec, + clippy::needless_late_init, + clippy::single_match, + clippy::no_effect // only fires _after_ the fix +)] fn f() -> i32 { println!("side effect"); @@ -102,3 +107,20 @@ fn issue_14681() { foo(&[Some(Some(S::new())); 0]); //~^ zero_repeat_side_effects } + +fn issue_15824() { + fn f() {} + + match 0 { + 0 => _ = [f(); 0], + //~^ zero_repeat_side_effects + _ => {}, + } + + let mut a = [(); 0]; + match 0 { + 0 => a = [f(); 0], + //~^ zero_repeat_side_effects + _ => {}, + } +} diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr index 49e850d035343..f376a1501b001 100644 --- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr +++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr @@ -1,5 +1,5 @@ error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:17:5 + --> tests/ui/zero_repeat_side_effects.rs:22:5 | LL | let a = [f(); 0]; | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + let a: [i32; 0] = []; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:20:5 + --> tests/ui/zero_repeat_side_effects.rs:25:5 | LL | b = [f(); 0]; | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL ~ b = [] as [i32; 0]; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:25:5 + --> tests/ui/zero_repeat_side_effects.rs:30:5 | LL | let c = vec![f(); 0]; | ^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let c: std::vec::Vec = vec![]; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:28:5 + --> tests/ui/zero_repeat_side_effects.rs:33:5 | LL | d = vec![f(); 0]; | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL ~ d = vec![] as std::vec::Vec; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:32:5 + --> tests/ui/zero_repeat_side_effects.rs:37:5 | LL | let e = [println!("side effect"); 0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let e: [(); 0] = []; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:36:5 + --> tests/ui/zero_repeat_side_effects.rs:41:5 | LL | let g = [{ f() }; 0]; | ^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + let g: [i32; 0] = []; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:40:10 + --> tests/ui/zero_repeat_side_effects.rs:45:10 | LL | drop(vec![f(); 0]); | ^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ }); | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:44:5 + --> tests/ui/zero_repeat_side_effects.rs:49:5 | LL | vec![f(); 0]; | ^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL ~ vec![] as std::vec::Vec; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:46:5 + --> tests/ui/zero_repeat_side_effects.rs:51:5 | LL | [f(); 0]; | ^^^^^^^^ @@ -111,7 +111,7 @@ LL ~ [] as [i32; 0]; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:100:10 + --> tests/ui/zero_repeat_side_effects.rs:105:10 | LL | foo(&[Some(f()); 0]); | ^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL ~ }); | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:102:10 + --> tests/ui/zero_repeat_side_effects.rs:107:10 | LL | foo(&[Some(Some(S::new())); 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,5 +138,33 @@ LL + [] as [std::option::Option>; 0] LL ~ }); | -error: aborting due to 11 previous errors +error: expression with side effects as the initial value in a zero-sized array initializer + --> tests/ui/zero_repeat_side_effects.rs:115:14 + | +LL | 0 => _ = [f(); 0], + | ^^^^^^^^^^^^ + | +help: consider performing the side effect separately + | +LL ~ 0 => { +LL + f(); +LL + _ = [] as [(); 0] +LL ~ }, + | + +error: expression with side effects as the initial value in a zero-sized array initializer + --> tests/ui/zero_repeat_side_effects.rs:122:14 + | +LL | 0 => a = [f(); 0], + | ^^^^^^^^^^^^ + | +help: consider performing the side effect separately + | +LL ~ 0 => { +LL + f(); +LL + a = [] as [(); 0] +LL ~ }, + | + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 3bf62b6b3bbaf..09dec7675e7e5 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -22,9 +22,6 @@ allow-unauthenticated = [ [mentions."clippy_lints/src/doc"] cc = ["@notriddle"] -# Prevents mentions in commits to avoid users being spammed -[no-mentions] - # Have rustbot inform users about the *No Merge Policy* [no-merges] exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust @@ -65,6 +62,7 @@ users_on_vacation = [ "Manishearth", "Alexendoo", "y21", + "blyxyas", ] [assign.owners] @@ -77,7 +75,6 @@ users_on_vacation = [ "@Alexendoo", "@dswij", "@Jarcho", - "@blyxyas", "@y21", "@samueltardieu", ] diff --git a/src/tools/clippy/util/gh-pages/style.css b/src/tools/clippy/util/gh-pages/style.css index 242e2227ed949..ce478a3e18d0b 100644 --- a/src/tools/clippy/util/gh-pages/style.css +++ b/src/tools/clippy/util/gh-pages/style.css @@ -637,14 +637,14 @@ pre, hr { display: flex; } -ul.dropdown-menu li.checkbox > button { +#menu-filters ul.dropdown-menu li.checkbox > button { border: 0; width: 100%; background: var(--theme-popup-bg); color: var(--fg); } -ul.dropdown-menu li.checkbox > button:hover { +#menu-filters ul.dropdown-menu li.checkbox > button:hover { background: var(--theme-hover); box-shadow: none; } diff --git a/src/tools/miri/tests/fail/closures/deref-in-pattern.rs b/src/tools/miri/tests/fail/closures/deref-in-pattern.rs new file mode 100644 index 0000000000000..c729469c78b0e --- /dev/null +++ b/src/tools/miri/tests/fail/closures/deref-in-pattern.rs @@ -0,0 +1,20 @@ +// This test serves to document the change in semantics introduced by +// rust-lang/rust#138961. +// +// A corollary of partial-pattern.rs: while the tuple access testcase makes +// it clear why these semantics are useful, it is actually the dereference +// being performed by the pattern that matters. + +fn main() { + // the inner reference is dangling + let x: &&u32 = unsafe { + let x: u32 = 42; + &&* &raw const x + }; + + let _ = || { //~ ERROR: encountered a dangling reference + match x { + &&_y => {}, + } + }; +} diff --git a/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr b/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr new file mode 100644 index 0000000000000..1264f4e3fb95a --- /dev/null +++ b/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) + --> tests/fail/closures/deref-in-pattern.rs:LL:CC + | +LL | let _ = || { + | _____________^ +LL | | match x { +LL | | &&_y => {}, +LL | | } +LL | | }; + | |_____^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/closures/partial-pattern.rs b/src/tools/miri/tests/fail/closures/partial-pattern.rs new file mode 100644 index 0000000000000..cb64462081802 --- /dev/null +++ b/src/tools/miri/tests/fail/closures/partial-pattern.rs @@ -0,0 +1,28 @@ +// This test serves to document the change in semantics introduced by +// rust-lang/rust#138961. +// +// Previously, the closure would capture the entirety of x, and access *(*x).0 +// when called. Now, the closure only captures *(*x).0, which means that +// a &*(*x).0 reborrow happens when the closure is constructed. +// +// Hence, if one of the references is dangling, this constitutes newly introduced UB +// in the case where the closure doesn't get called. This isn't a big deal, +// because while opsem only now considers this to be UB, the unsafe code +// guidelines have long recommended against any handling of dangling references. + +fn main() { + // the inner references are dangling + let x: &(&u32, &u32) = unsafe { + let a = 21; + let b = 37; + let ra = &* &raw const a; + let rb = &* &raw const b; + &(ra, rb) + }; + + let _ = || { //~ ERROR: encountered a dangling reference + match x { + (&_y, _) => {}, + } + }; +} diff --git a/src/tools/miri/tests/fail/closures/partial-pattern.stderr b/src/tools/miri/tests/fail/closures/partial-pattern.stderr new file mode 100644 index 0000000000000..5b7ee35ecc736 --- /dev/null +++ b/src/tools/miri/tests/fail/closures/partial-pattern.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) + --> tests/fail/closures/partial-pattern.rs:LL:CC + | +LL | let _ = || { + | _____________^ +LL | | match x { +LL | | (&_y, _) => {}, +LL | | } +LL | | }; + | |_____^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/closures/uninhabited-variant.rs b/src/tools/miri/tests/fail/closures/uninhabited-variant.rs new file mode 100644 index 0000000000000..9c50fdc13a35f --- /dev/null +++ b/src/tools/miri/tests/fail/closures/uninhabited-variant.rs @@ -0,0 +1,31 @@ +// Motivated by rust-lang/rust#138961, this shows how invalid discriminants interact with +// closure captures. +#![feature(never_type)] + +#[repr(C)] +#[allow(dead_code)] +enum E { + V0, // discriminant: 0 + V1, // 1 + V2(!), // 2 +} + +fn main() { + assert_eq!(std::mem::size_of::(), 4); + + let val = 2u32; + let ptr = (&raw const val).cast::(); + let r = unsafe { &*ptr }; + let f = || { + // After rust-lang/rust#138961, constructing the closure performs a reborrow of r. + // Nevertheless, the discriminant is only actually inspected when the closure + // is called. + match r { //~ ERROR: read discriminant of an uninhabited enum variant + E::V0 => {} + E::V1 => {} + E::V2(_) => {} + } + }; + + f(); +} diff --git a/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr new file mode 100644 index 0000000000000..995a5e3eac146 --- /dev/null +++ b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: read discriminant of an uninhabited enum variant + --> tests/fail/closures/uninhabited-variant.rs:LL:CC + | +LL | match r { + | ^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside closure at tests/fail/closures/uninhabited-variant.rs:LL:CC +note: inside `main` + --> tests/fail/closures/uninhabited-variant.rs:LL:CC + | +LL | f(); + | ^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/crashes/119786.rs b/tests/crashes/119786-1.rs similarity index 100% rename from tests/crashes/119786.rs rename to tests/crashes/119786-1.rs diff --git a/tests/crashes/119786-2.rs b/tests/crashes/119786-2.rs new file mode 100644 index 0000000000000..76c5deb4605ae --- /dev/null +++ b/tests/crashes/119786-2.rs @@ -0,0 +1,15 @@ +//@ known-bug: #119786 +//@ edition:2021 + +fn enum_upvar() { + type T = impl Copy; + let foo: T = Some((1u32, 2u32)); + let x = move || { + match foo { + None => (), + Some(_) => (), + } + }; +} + +pub fn main() {} diff --git a/tests/crashes/119786-3.rs b/tests/crashes/119786-3.rs new file mode 100644 index 0000000000000..34bb90fd0fae3 --- /dev/null +++ b/tests/crashes/119786-3.rs @@ -0,0 +1,15 @@ +//@ known-bug: #119786 +//@ edition:2021 + +fn enum_upvar() { + type T = impl Copy; + let foo: T = Some((1u32, 2u32)); + let x = move || { + match foo { + None => (), + Some((a, b)) => (), + } + }; +} + +pub fn main() {} diff --git a/tests/crashes/137467-1.rs b/tests/crashes/137467-1.rs deleted file mode 100644 index b6bff2bdc4e86..0000000000000 --- a/tests/crashes/137467-1.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #137467 -//@ edition: 2021 -enum Camera { - Normal { base_transform: i32 }, - Volume { transform: i32 }, -} - -fn draw_ui(camera: &mut Camera) { - || { - let (Camera::Normal { - base_transform: _transform, - } - | Camera::Volume { - transform: _transform, - }) = camera; - }; -} diff --git a/tests/crashes/137467-2.rs b/tests/crashes/137467-2.rs deleted file mode 100644 index a70ea92b22dc2..0000000000000 --- a/tests/crashes/137467-2.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #137467 -//@ edition: 2021 - -enum Camera { - Normal { base_transform: i32 }, - Volume { transform: i32 }, -} - -fn draw_ui(camera: &mut Camera) { - || { - let (Camera::Normal { - base_transform: _, - } - | Camera::Volume { - transform: _, - }) = camera; - }; -} diff --git a/tests/crashes/137467-3.rs b/tests/crashes/137467-3.rs deleted file mode 100644 index cb81a9a912e7c..0000000000000 --- a/tests/crashes/137467-3.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #137467 -//@ edition: 2021 - -fn meow(x: (u32, u32, u32)) { - let f = || { - let ((0, a, _) | (_, _, a)) = x; - }; -} diff --git a/tests/crashes/140011.rs b/tests/crashes/140011.rs deleted file mode 100644 index b9d57a2822d21..0000000000000 --- a/tests/crashes/140011.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #140011 -//@compile-flags: -Wrust-2021-incompatible-closure-captures -enum b { - c(d), - e(f), -} -struct f; -fn g() { - let h; - || b::e(a) = h; -} diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir index b43af549b232c..9ff1a90ab820b 100644 --- a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir @@ -4,18 +4,16 @@ fn foo::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_fake yields () { debug _task_context => _2; - debug f => (*(_1.0: &&Foo)); + debug f => (*(_1.0: &Foo)); let mut _0: (); let mut _3: &Foo; let mut _4: &&Foo; - let mut _5: &&&Foo; - let mut _6: isize; - let mut _7: bool; + let mut _5: isize; + let mut _6: bool; bb0: { - PlaceMention((*(_1.0: &&Foo))); - _6 = discriminant((*(*(_1.0: &&Foo)))); - switchInt(move _6) -> [0: bb2, otherwise: bb1]; + _5 = discriminant((*(_1.0: &Foo))); + switchInt(move _5) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -32,17 +30,15 @@ yields () } bb4: { - FakeRead(ForMatchedPlace(None), (*(_1.0: &&Foo))); unreachable; } bb5: { - _3 = &fake shallow (*(*(_1.0: &&Foo))); - _4 = &fake shallow (*(_1.0: &&Foo)); - _5 = &fake shallow (_1.0: &&Foo); - StorageLive(_7); - _7 = const true; - switchInt(move _7) -> [0: bb8, otherwise: bb7]; + _3 = &fake shallow (*(_1.0: &Foo)); + _4 = &fake shallow (_1.0: &Foo); + StorageLive(_6); + _6 = const true; + switchInt(move _6) -> [0: bb8, otherwise: bb7]; } bb6: { @@ -50,10 +46,9 @@ yields () } bb7: { - StorageDead(_7); + StorageDead(_6); FakeRead(ForMatchGuard, _3); FakeRead(ForMatchGuard, _4); - FakeRead(ForMatchGuard, _5); _0 = const (); goto -> bb10; } @@ -63,7 +58,7 @@ yields () } bb9: { - StorageDead(_7); + StorageDead(_6); goto -> bb6; } diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir index 5623b6d64e973..4b745caf48c5a 100644 --- a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir @@ -4,18 +4,16 @@ fn foo::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_fa yields () { debug _task_context => _2; - debug f => (_1.0: &Foo); + debug f => (*(_1.0: &Foo)); let mut _0: (); let mut _3: &Foo; let mut _4: &&Foo; - let mut _5: &&&Foo; - let mut _6: isize; - let mut _7: bool; + let mut _5: isize; + let mut _6: bool; bb0: { - PlaceMention((_1.0: &Foo)); - _6 = discriminant((*(_1.0: &Foo))); - switchInt(move _6) -> [0: bb2, otherwise: bb1]; + _5 = discriminant((*(_1.0: &Foo))); + switchInt(move _5) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -29,24 +27,22 @@ yields () bb3: { _3 = &fake shallow (*(_1.0: &Foo)); - _4 = &fake shallow (_1.0: &Foo); nop; - StorageLive(_7); - _7 = const true; - switchInt(move _7) -> [0: bb5, otherwise: bb4]; + StorageLive(_6); + _6 = const true; + switchInt(move _6) -> [0: bb5, otherwise: bb4]; } bb4: { - StorageDead(_7); + StorageDead(_6); FakeRead(ForMatchGuard, _3); FakeRead(ForMatchGuard, _4); - FakeRead(ForMatchGuard, _5); _0 = const (); goto -> bb6; } bb5: { - StorageDead(_7); + StorageDead(_6); falseEdge -> [real: bb1, imaginary: bb1]; } diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index 93741f26275bd..b6fddc88e19b8 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -30,7 +30,7 @@ pub extern "C" fn inline_never() { } #[unsafe(naked)] -#[cfg_attr(all(), inline(never))] +#[cfg_attr(true, inline(never))] //~^ ERROR [E0736] pub extern "C" fn conditional_inline_never() { naked_asm!(""); diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr index 91140a301edc9..785ecf734b9d2 100644 --- a/tests/ui/asm/naked-functions-inline.stderr +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -23,12 +23,12 @@ LL | #[inline(never)] | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:33:19 + --> $DIR/naked-functions-inline.rs:33:18 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here -LL | #[cfg_attr(all(), inline(never))] - | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` +LL | #[cfg_attr(true, inline(never))] + | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error: aborting due to 4 previous errors diff --git a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs index 6a9853b2f6fc6..7d05e08b26237 100644 --- a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs @@ -1,6 +1,6 @@ //@ build-pass -#[cfg_attr(all(), unsafe(no_mangle))] +#[cfg_attr(true, unsafe(no_mangle))] fn a() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs index 19046c08ca8bd..a034b7246a347 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs @@ -1,9 +1,9 @@ //@ edition: 2024 -#[unsafe(cfg(any()))] //~ ERROR: is not an unsafe attribute +#[unsafe(cfg(false))] //~ ERROR: is not an unsafe attribute fn a() {} -#[unsafe(cfg_attr(any(), allow(dead_code)))] //~ ERROR: is not an unsafe attribute +#[unsafe(cfg_attr(false, allow(dead_code)))] //~ ERROR: is not an unsafe attribute fn b() {} #[unsafe(test)] //~ ERROR: is not an unsafe attribute diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr index b549a638d5eae..dec8c4d3542b4 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr @@ -1,7 +1,7 @@ error: `cfg` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:3:3 | -LL | #[unsafe(cfg(any()))] +LL | #[unsafe(cfg(false))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -9,7 +9,7 @@ LL | #[unsafe(cfg(any()))] error: `cfg_attr` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:6:3 | -LL | #[unsafe(cfg_attr(any(), allow(dead_code)))] +LL | #[unsafe(cfg_attr(false, allow(dead_code)))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs index 5c57767b3b964..c08b0ed995e52 100644 --- a/tests/ui/attributes/unsafe/unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs @@ -6,7 +6,7 @@ fn a() {} #[unsafe(export_name = "foo")] fn b() {} -#[cfg_attr(any(), unsafe(no_mangle))] +#[cfg_attr(false, unsafe(no_mangle))] static VAR2: u32 = 1; fn main() {} diff --git a/tests/ui/cfg/conditional-compilation-struct-11085.rs b/tests/ui/cfg/conditional-compilation-struct-11085.rs index cd6dded54d30b..8fdc88be37d24 100644 --- a/tests/ui/cfg/conditional-compilation-struct-11085.rs +++ b/tests/ui/cfg/conditional-compilation-struct-11085.rs @@ -11,7 +11,7 @@ struct Foo { } struct Foo2 { - #[cfg(all())] + #[cfg(true)] foo: isize, } diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index 0739e877bfd14..8761197891f5e 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -151,5 +151,5 @@ mod test_methods { } } -#[cfg(any())] +#[cfg(false)] mod nonexistent_file; // Check that unconfigured non-inline modules are not loaded or parsed. diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs index c5d86a27d522d..8e79ce8d1546f 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs @@ -3,14 +3,14 @@ //! expansion works from outside to inside, eventually applying the innermost //! conditional compilation directive. //! -//! In this test, `cfg_attr(all(), cfg_attr(all(), cfg(false)))` should expand to: -//! 1. `cfg_attr(all(), cfg(false))` (outer cfg_attr applied) +//! In this test, `cfg_attr(true, cfg_attr(true, cfg(false)))` should expand to: +//! 1. `cfg_attr(true, cfg(false))` (outer cfg_attr applied) //! 2. `cfg(false)` (inner cfg_attr applied) //! 3. Function `f` is excluded from compilation //! //! Added in . -#[cfg_attr(all(), cfg_attr(all(), cfg(false)))] //~ NOTE the item is gated here +#[cfg_attr(true, cfg_attr(true, cfg(false)))] //~ NOTE the item is gated here fn f() {} //~ NOTE found an item that was configured out fn main() { diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr index 3f833bd558b86..e93a5433d9791 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr @@ -7,8 +7,8 @@ LL | f() note: found an item that was configured out --> $DIR/nested-cfg-attr-conditional-compilation.rs:14:4 | -LL | #[cfg_attr(all(), cfg_attr(all(), cfg(false)))] - | ----- the item is gated here +LL | #[cfg_attr(true, cfg_attr(true, cfg(false)))] + | ----- the item is gated here LL | fn f() {} | ^ diff --git a/tests/ui/check-cfg/false.rs b/tests/ui/check-cfg/false.rs new file mode 100644 index 0000000000000..f7ed43ccfa953 --- /dev/null +++ b/tests/ui/check-cfg/false.rs @@ -0,0 +1,61 @@ +//! Check that `cfg(false)` is suggested instead of cfg(FALSE) +// +//@ check-pass +//@ no-auto-check-cfg +//@ compile-flags: --check-cfg=cfg() + +#[cfg(FALSE)] +//~^ WARNING unexpected `cfg` condition name: `FALSE` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `false` (notice the capitalization). +pub fn a() {} + +#[cfg(False)] +//~^ WARNING unexpected `cfg` condition name: `False` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `false` (notice the capitalization). +pub fn b() {} + +#[cfg(r#false)] +//~^ WARNING unexpected `cfg` condition name: `r#false` +//~| HELP: to expect this configuration use +// No capitalization help for r#false +pub fn c() {} + +#[cfg(r#False)] +//~^ WARNING unexpected `cfg` condition name: `False` +//~| HELP: to expect this configuration use +// No capitalization help for r#False +pub fn d() {} + +#[cfg(false)] +pub fn e() {} + +#[cfg(TRUE)] +//~^ WARNING unexpected `cfg` condition name: `TRUE` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `true` (notice the capitalization). +pub fn f() {} + +#[cfg(True)] +//~^ WARNING unexpected `cfg` condition name: `True` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `true` (notice the capitalization). +pub fn g() {} + +#[cfg(r#true)] +//~^ WARNING unexpected `cfg` condition name: `r#true` +//~| HELP: to expect this configuration use +// No capitalization help for r#true +pub fn h() {} + +#[cfg(r#True)] +//~^ WARNING unexpected `cfg` condition name: `True` +//~| HELP: to expect this configuration use +// No capitalization help for r#True +pub fn i() {} + +#[cfg(true)] +pub fn j() {} + +pub fn main() {} diff --git a/tests/ui/check-cfg/false.stderr b/tests/ui/check-cfg/false.stderr new file mode 100644 index 0000000000000..f4480a3dc67e7 --- /dev/null +++ b/tests/ui/check-cfg/false.stderr @@ -0,0 +1,95 @@ +warning: unexpected `cfg` condition name: `FALSE` + --> $DIR/false.rs:7:7 + | +LL | #[cfg(FALSE)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(FALSE)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: you may have meant to use `false` (notice the capitalization). Doing so makes this predicate evaluate to `false` unconditionally + | +LL - #[cfg(FALSE)] +LL + #[cfg(false)] + | + +warning: unexpected `cfg` condition name: `False` + --> $DIR/false.rs:13:7 + | +LL | #[cfg(False)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(False)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `false` (notice the capitalization). Doing so makes this predicate evaluate to `false` unconditionally (notice the capitalization) + | +LL - #[cfg(False)] +LL + #[cfg(false)] + | + +warning: unexpected `cfg` condition name: `r#false` + --> $DIR/false.rs:19:7 + | +LL | #[cfg(r#false)] + | ^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(r#false)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `False` + --> $DIR/false.rs:25:7 + | +LL | #[cfg(r#False)] + | ^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(False)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `TRUE` + --> $DIR/false.rs:34:7 + | +LL | #[cfg(TRUE)] + | ^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(TRUE)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `true` (notice the capitalization). Doing so makes this predicate evaluate to `true` unconditionally + | +LL - #[cfg(TRUE)] +LL + #[cfg(true)] + | + +warning: unexpected `cfg` condition name: `True` + --> $DIR/false.rs:40:7 + | +LL | #[cfg(True)] + | ^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(True)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `true` (notice the capitalization). Doing so makes this predicate evaluate to `true` unconditionally + | +LL - #[cfg(True)] +LL + #[cfg(true)] + | + +warning: unexpected `cfg` condition name: `r#true` + --> $DIR/false.rs:46:7 + | +LL | #[cfg(r#true)] + | ^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(r#true)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `True` + --> $DIR/false.rs:52:7 + | +LL | #[cfg(r#True)] + | ^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(True)` + = note: see for more information about checking conditional configuration + +warning: 8 warnings emitted + diff --git a/tests/ui/closures/2229_closure_analysis/capture-enums.rs b/tests/ui/closures/2229_closure_analysis/capture-enums.rs index d9c06a68c95b9..4c600ccdaa438 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-enums.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-enums.rs @@ -22,6 +22,7 @@ fn multi_variant_enum() { //~| ERROR Min Capture analysis includes: if let Info::Point(_, _, str) = point { //~^ NOTE: Capturing point[] -> Immutable + //~| NOTE: Capturing point[] -> Immutable //~| NOTE: Capturing point[(2, 0)] -> ByValue //~| NOTE: Min Capture point[] -> ByValue println!("{}", str); @@ -29,6 +30,7 @@ fn multi_variant_enum() { if let Info::Meta(_, v) = meta { //~^ NOTE: Capturing meta[] -> Immutable + //~| NOTE: Capturing meta[] -> Immutable //~| NOTE: Capturing meta[(1, 1)] -> ByValue //~| NOTE: Min Capture meta[] -> ByValue println!("{:?}", v); diff --git a/tests/ui/closures/2229_closure_analysis/capture-enums.stderr b/tests/ui/closures/2229_closure_analysis/capture-enums.stderr index 89a879cec468b..b62384ffe12e0 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-enums.stderr +++ b/tests/ui/closures/2229_closure_analysis/capture-enums.stderr @@ -9,7 +9,7 @@ LL | let c = #[rustc_capture_analysis] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: attributes on expressions are experimental - --> $DIR/capture-enums.rs:48:13 + --> $DIR/capture-enums.rs:50:13 | LL | let c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,18 +34,28 @@ note: Capturing point[] -> Immutable | LL | if let Info::Point(_, _, str) = point { | ^^^^^ +note: Capturing point[] -> Immutable + --> $DIR/capture-enums.rs:23:41 + | +LL | if let Info::Point(_, _, str) = point { + | ^^^^^ note: Capturing point[(2, 0)] -> ByValue --> $DIR/capture-enums.rs:23:41 | LL | if let Info::Point(_, _, str) = point { | ^^^^^ note: Capturing meta[] -> Immutable - --> $DIR/capture-enums.rs:30:35 + --> $DIR/capture-enums.rs:31:35 + | +LL | if let Info::Meta(_, v) = meta { + | ^^^^ +note: Capturing meta[] -> Immutable + --> $DIR/capture-enums.rs:31:35 | LL | if let Info::Meta(_, v) = meta { | ^^^^ note: Capturing meta[(1, 1)] -> ByValue - --> $DIR/capture-enums.rs:30:35 + --> $DIR/capture-enums.rs:31:35 | LL | if let Info::Meta(_, v) = meta { | ^^^^ @@ -67,13 +77,13 @@ note: Min Capture point[] -> ByValue LL | if let Info::Point(_, _, str) = point { | ^^^^^ note: Min Capture meta[] -> ByValue - --> $DIR/capture-enums.rs:30:35 + --> $DIR/capture-enums.rs:31:35 | LL | if let Info::Meta(_, v) = meta { | ^^^^ error: First Pass analysis includes: - --> $DIR/capture-enums.rs:52:5 + --> $DIR/capture-enums.rs:54:5 | LL | / || { LL | | @@ -85,13 +95,13 @@ LL | | }; | |_____^ | note: Capturing point[(2, 0)] -> ByValue - --> $DIR/capture-enums.rs:55:47 + --> $DIR/capture-enums.rs:57:47 | LL | let SingleVariant::Point(_, _, str) = point; | ^^^^^ error: Min Capture analysis includes: - --> $DIR/capture-enums.rs:52:5 + --> $DIR/capture-enums.rs:54:5 | LL | / || { LL | | @@ -103,7 +113,7 @@ LL | | }; | |_____^ | note: Min Capture point[(2, 0)] -> ByValue - --> $DIR/capture-enums.rs:55:47 + --> $DIR/capture-enums.rs:57:47 | LL | let SingleVariant::Point(_, _, str) = point; | ^^^^^ diff --git a/tests/ui/closures/2229_closure_analysis/deref-mut-in-pattern.rs b/tests/ui/closures/2229_closure_analysis/deref-mut-in-pattern.rs new file mode 100644 index 0000000000000..b2c0eac9efa27 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/deref-mut-in-pattern.rs @@ -0,0 +1,54 @@ +// Newly accepted examples as a result of the changes introduced in #138961. +// +//@ edition:2024 +//@ check-pass +#![allow(unused_assignments)] + +// Reading the length as part of a pattern captures the pointee. +fn f() { + let mut x: &mut [u8] = &mut [1, 2, 3]; + let c = || { + match x { + [] => (), + _ => (), + } + }; + x = &mut []; + c(); +} + +// Plain old deref as part of pattern behaves similarly +fn g() { + let mut x: &mut bool = &mut false; + let mut t = true; + let c = || { + match x { + true => (), + false => (), + } + }; + x = &mut t; + c(); +} + +// Like f, but the lifetime implications are expressed in terms of +// returning a closure. +fn f2<'l: 's, 's>(x: &'s mut &'l [u8]) -> impl Fn() + 'l { + || match *x { + &[] => (), + _ => (), + } +} + +// Related testcase that was already accepted before +fn f3<'l: 's, 's>(x: &'s mut &'l [u8]) -> impl Fn() + 'l { + || match **x { + [] => (), + _ => (), + } +} + +fn main() { + f(); + g(); +} diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr index d82db0481a06f..3f5fe9eda423f 100644 --- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr @@ -4,7 +4,7 @@ error[E0505]: cannot move out of `ts` because it is borrowed LL | let _b = || { match ts { | -- -- borrow occurs due to use in closure | | - | borrow of `ts` occurs here + | borrow of `ts.x` occurs here ... LL | let mut mut_ts = ts; | ^^ move out of `ts` occurs here diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs index 40330af4088c2..16cb9d7355da5 100644 --- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs +++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs @@ -64,9 +64,8 @@ fn test_6_should_capture_single_variant() { //~^ ERROR First Pass analysis includes: //~| ERROR Min Capture analysis includes: match variant { - //~^ NOTE: Capturing variant[] -> Immutable - //~| NOTE: Capturing variant[(0, 0)] -> Immutable - //~| NOTE: Min Capture variant[] -> Immutable + //~^ NOTE: Capturing variant[(0, 0)] -> Immutable + //~| NOTE: Min Capture variant[(0, 0)] -> Immutable SingleVariant::Points(a) => { println!("{:?}", a); } @@ -149,8 +148,8 @@ fn test_7_should_capture_slice_len() { //~^ ERROR First Pass analysis includes: //~| ERROR Min Capture analysis includes: match slice { - //~^ NOTE: Capturing slice[] -> Immutable - //~| NOTE: Min Capture slice[] -> Immutable + //~^ NOTE: Capturing slice[Deref] -> Immutable + //~| NOTE: Min Capture slice[Deref] -> Immutable [_,_,_] => {}, _ => {} } @@ -161,8 +160,8 @@ fn test_7_should_capture_slice_len() { //~^ ERROR First Pass analysis includes: //~| ERROR Min Capture analysis includes: match slice { - //~^ NOTE: Capturing slice[] -> Immutable - //~| NOTE: Min Capture slice[] -> Immutable + //~^ NOTE: Capturing slice[Deref] -> Immutable + //~| NOTE: Min Capture slice[Deref] -> Immutable [] => {}, _ => {} } @@ -173,8 +172,8 @@ fn test_7_should_capture_slice_len() { //~^ ERROR First Pass analysis includes: //~| ERROR Min Capture analysis includes: match slice { - //~^ NOTE: Capturing slice[] -> Immutable - //~| NOTE: Min Capture slice[] -> Immutable + //~^ NOTE: Capturing slice[Deref] -> Immutable + //~| NOTE: Min Capture slice[Deref] -> Immutable [_, .. ,_] => {}, _ => {} } diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr index e7e5e7f7fa1bf..73c685e152765 100644 --- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr @@ -65,11 +65,6 @@ LL | | match variant { LL | | }; | |_____^ | -note: Capturing variant[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:66:15 - | -LL | match variant { - | ^^^^^^^ note: Capturing variant[(0, 0)] -> Immutable --> $DIR/patterns-capture-analysis.rs:66:15 | @@ -87,14 +82,14 @@ LL | | match variant { LL | | }; | |_____^ | -note: Min Capture variant[] -> Immutable +note: Min Capture variant[(0, 0)] -> Immutable --> $DIR/patterns-capture-analysis.rs:66:15 | LL | match variant { | ^^^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:83:5 + --> $DIR/patterns-capture-analysis.rs:82:5 | LL | / || { LL | | @@ -105,7 +100,7 @@ LL | | }; | |_____^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:95:5 + --> $DIR/patterns-capture-analysis.rs:94:5 | LL | / || { LL | | @@ -116,7 +111,7 @@ LL | | }; | |_____^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:108:5 + --> $DIR/patterns-capture-analysis.rs:107:5 | LL | / || { LL | | @@ -127,7 +122,7 @@ LL | | }; | |_____^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:130:5 + --> $DIR/patterns-capture-analysis.rs:129:5 | LL | / || { LL | | @@ -138,13 +133,13 @@ LL | | }; | |_____^ | note: Capturing variant[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:133:15 + --> $DIR/patterns-capture-analysis.rs:132:15 | LL | match variant { | ^^^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:130:5 + --> $DIR/patterns-capture-analysis.rs:129:5 | LL | / || { LL | | @@ -155,13 +150,13 @@ LL | | }; | |_____^ | note: Min Capture variant[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:133:15 + --> $DIR/patterns-capture-analysis.rs:132:15 | LL | match variant { | ^^^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:148:5 + --> $DIR/patterns-capture-analysis.rs:147:5 | LL | / || { LL | | @@ -171,14 +166,14 @@ LL | | match slice { LL | | }; | |_____^ | -note: Capturing slice[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:151:15 +note: Capturing slice[Deref] -> Immutable + --> $DIR/patterns-capture-analysis.rs:150:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:148:5 + --> $DIR/patterns-capture-analysis.rs:147:5 | LL | / || { LL | | @@ -188,14 +183,14 @@ LL | | match slice { LL | | }; | |_____^ | -note: Min Capture slice[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:151:15 +note: Min Capture slice[Deref] -> Immutable + --> $DIR/patterns-capture-analysis.rs:150:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:160:5 + --> $DIR/patterns-capture-analysis.rs:159:5 | LL | / || { LL | | @@ -205,14 +200,14 @@ LL | | match slice { LL | | }; | |_____^ | -note: Capturing slice[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:163:15 +note: Capturing slice[Deref] -> Immutable + --> $DIR/patterns-capture-analysis.rs:162:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:160:5 + --> $DIR/patterns-capture-analysis.rs:159:5 | LL | / || { LL | | @@ -222,14 +217,14 @@ LL | | match slice { LL | | }; | |_____^ | -note: Min Capture slice[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:163:15 +note: Min Capture slice[Deref] -> Immutable + --> $DIR/patterns-capture-analysis.rs:162:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:172:5 + --> $DIR/patterns-capture-analysis.rs:171:5 | LL | / || { LL | | @@ -239,14 +234,14 @@ LL | | match slice { LL | | }; | |_____^ | -note: Capturing slice[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:175:15 +note: Capturing slice[Deref] -> Immutable + --> $DIR/patterns-capture-analysis.rs:174:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:172:5 + --> $DIR/patterns-capture-analysis.rs:171:5 | LL | / || { LL | | @@ -256,14 +251,14 @@ LL | | match slice { LL | | }; | |_____^ | -note: Min Capture slice[] -> Immutable - --> $DIR/patterns-capture-analysis.rs:175:15 +note: Min Capture slice[Deref] -> Immutable + --> $DIR/patterns-capture-analysis.rs:174:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:189:5 + --> $DIR/patterns-capture-analysis.rs:188:5 | LL | / || { LL | | diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.rs b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.rs new file mode 100644 index 0000000000000..c7f367cc48ab9 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.rs @@ -0,0 +1,22 @@ +// This example used to compile, but the fact that it should was never properly +// discussed. With further experience, we concluded that capture precision +// depending on whether some types are inhabited goes too far, introducing a +// bunch of headaches without much benefit. +//@ edition:2021 +enum Void {} + +pub fn main() { + let mut r = Result::::Err((0, 0)); + let mut f = || { + let Err((ref mut a, _)) = r; + *a = 1; + }; + let mut g = || { + //~^ ERROR: cannot borrow `r` as mutable more than once at a time + let Err((_, ref mut b)) = r; + *b = 2; + }; + f(); + g(); + assert!(matches!(r, Err((1, 2)))); +} diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.stderr b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.stderr new file mode 100644 index 0000000000000..7f4c8942b0d91 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.stderr @@ -0,0 +1,20 @@ +error[E0499]: cannot borrow `r` as mutable more than once at a time + --> $DIR/only-inhabited-variant-stable.rs:14:17 + | +LL | let mut f = || { + | -- first mutable borrow occurs here +LL | let Err((ref mut a, _)) = r; + | - first borrow occurs due to use of `r` in closure +... +LL | let mut g = || { + | ^^ second mutable borrow occurs here +LL | +LL | let Err((_, ref mut b)) = r; + | - second borrow occurs due to use of `r` in closure +... +LL | f(); + | - first borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.exhaustive_patterns.stderr b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.exhaustive_patterns.stderr new file mode 100644 index 0000000000000..58a5348aa391a --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.exhaustive_patterns.stderr @@ -0,0 +1,20 @@ +error[E0499]: cannot borrow `r` as mutable more than once at a time + --> $DIR/only-inhabited-variant.rs:16:17 + | +LL | let mut f = || { + | -- first mutable borrow occurs here +LL | let Err((ref mut a, _)) = r; + | - first borrow occurs due to use of `r` in closure +... +LL | let mut g = || { + | ^^ second mutable borrow occurs here +LL | +LL | let Err((_, ref mut b)) = r; + | - second borrow occurs due to use of `r` in closure +... +LL | f(); + | - first borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.normal.stderr b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.normal.stderr new file mode 100644 index 0000000000000..58a5348aa391a --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.normal.stderr @@ -0,0 +1,20 @@ +error[E0499]: cannot borrow `r` as mutable more than once at a time + --> $DIR/only-inhabited-variant.rs:16:17 + | +LL | let mut f = || { + | -- first mutable borrow occurs here +LL | let Err((ref mut a, _)) = r; + | - first borrow occurs due to use of `r` in closure +... +LL | let mut g = || { + | ^^ second mutable borrow occurs here +LL | +LL | let Err((_, ref mut b)) = r; + | - second borrow occurs due to use of `r` in closure +... +LL | f(); + | - first borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.rs similarity index 55% rename from tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs rename to tests/ui/closures/2229_closure_analysis/only-inhabited-variant.rs index 74f37b514e4a4..4638387347269 100644 --- a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs +++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.rs @@ -1,8 +1,9 @@ -// Test precise capture of a multi-variant enum (when remaining variants are -// visibly uninhabited). +// This example used to compile, but the fact that it should was never properly +// discussed. With further experience, we concluded that capture precision +// depending on whether some types are inhabited goes too far, introducing a +// bunch of headaches without much benefit. //@ revisions: normal exhaustive_patterns //@ edition:2021 -//@ run-pass #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] #![feature(never_type)] @@ -13,6 +14,7 @@ pub fn main() { *a = 1; }; let mut g = || { + //~^ ERROR: cannot borrow `r` as mutable more than once at a time let Err((_, ref mut b)) = r; *b = 2; }; diff --git a/tests/ui/closures/at-pattern-weirdness-issue-137553.rs b/tests/ui/closures/at-pattern-weirdness-issue-137553.rs new file mode 100644 index 0000000000000..7c934d4a14339 --- /dev/null +++ b/tests/ui/closures/at-pattern-weirdness-issue-137553.rs @@ -0,0 +1,41 @@ +//@ edition:2024 +//@ check-pass + +// Background: +fn f1() { + let mut a = (21, 37); + // only captures a.0, example compiles fine + let mut f = || { + let (ref mut x, _) = a; + *x = 42; + }; + a.1 = 69; + f(); +} + +// This used to error out: +fn f2() { + let mut a = (21, 37); + // used to capture all of a, now captures only a.0 + let mut f = || { + match a { + (ref mut x, _) => *x = 42, + } + }; + a.1 = 69; + f(); +} + +// This was inconsistent with the following: +fn main() { + let mut a = (21, 37); + // the useless @-pattern would cause it to capture only a.0. now the + // behavior is consistent with the case that doesn't use the @-pattern + let mut f = || { + match a { + (ref mut x @ _, _) => *x = 42, + } + }; + a.1 = 69; + f(); +} diff --git a/tests/ui/closures/malformed-pattern-issue-140011.rs b/tests/ui/closures/malformed-pattern-issue-140011.rs new file mode 100644 index 0000000000000..18061613e9880 --- /dev/null +++ b/tests/ui/closures/malformed-pattern-issue-140011.rs @@ -0,0 +1,13 @@ +//@compile-flags: -Wrust-2021-incompatible-closure-captures +enum B { + C(D), //~ ERROR: cannot find type `D` in this scope + E(F), +} +struct F; +fn f(h: B) { + || { + let B::E(a) = h; //~ ERROR: refutable pattern in local binding + }; +} + +fn main() {} diff --git a/tests/ui/closures/malformed-pattern-issue-140011.stderr b/tests/ui/closures/malformed-pattern-issue-140011.stderr new file mode 100644 index 0000000000000..08122b8a7d2e5 --- /dev/null +++ b/tests/ui/closures/malformed-pattern-issue-140011.stderr @@ -0,0 +1,36 @@ +error[E0412]: cannot find type `D` in this scope + --> $DIR/malformed-pattern-issue-140011.rs:3:7 + | +LL | C(D), + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | enum B { + | +++ + +error[E0005]: refutable pattern in local binding + --> $DIR/malformed-pattern-issue-140011.rs:9:13 + | +LL | let B::E(a) = h; + | ^^^^^^^ pattern `B::C(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html +note: `B` defined here + --> $DIR/malformed-pattern-issue-140011.rs:2:6 + | +LL | enum B { + | ^ +LL | C(D), + | - not covered + = note: the matched value is of type `B` +help: you might want to use `let else` to handle the variant that isn't matched + | +LL | let B::E(a) = h else { todo!() }; + | ++++++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0005, E0412. +For more information about an error, try `rustc --explain E0005`. diff --git a/tests/ui/closures/or-patterns-issue-137467.rs b/tests/ui/closures/or-patterns-issue-137467.rs new file mode 100644 index 0000000000000..5a1e84e1c9a0d --- /dev/null +++ b/tests/ui/closures/or-patterns-issue-137467.rs @@ -0,0 +1,177 @@ +//@ edition:2024 +//@ check-pass + +const X: u32 = 0; + +fn match_literal(x: (u32, u32, u32)) { + let _ = || { + let ((0, a, _) | (_, _, a)) = x; + a + }; +} + +fn match_range(x: (u32, u32, u32)) { + let _ = || { + let ((0..5, a, _) | (_, _, a)) = x; + a + }; +} + +fn match_const(x: (u32, u32, u32)) { + let _ = || { + let ((X, a, _) | (_, _, a)) = x; + a + }; +} + +// related testcase reported in #138973 +fn without_bindings(x: u32) { + let _ = || { + let (0 | _) = x; + }; +} + +enum Choice { A, B } + +fn match_unit_variant(x: (Choice, u32, u32)) { + let _ = || { + let ((Choice::A, a, _) | (Choice::B, _, a)) = x; + a + }; +} + +struct Unit; + +fn match_unit_struct(mut x: (Unit, u32)) { + let r = &mut x.0; + let _ = || { + let (Unit, a) = x; + a + }; + + let _ = *r; +} + +enum Also { Unit } + +fn match_unit_enum(mut x: (Also, u32)) { + let r = &mut x.0; + let _ = || { + let (Also::Unit, a) = x; + a + }; + + let _ = *r; +} + +enum TEnum { + A(u32), + B(u32), +} + +enum SEnum { + A { a: u32 }, + B { a: u32 }, +} + +fn match_tuple_enum(x: TEnum) { + let _ = || { + let (TEnum::A(a) | TEnum::B(a)) = x; + a + }; +} + +fn match_struct_enum(x: SEnum) { + let _ = || { + let (SEnum::A { a } | SEnum::B { a }) = x; + a + }; +} + +enum TSingle { + A(u32, u32), +} + +enum SSingle { + A { a: u32, b: u32 }, +} + +struct TStruct(u32, u32); +struct SStruct { a: u32, b: u32 } + +fn match_struct(mut x: SStruct) { + let r = &mut x.a; + let _ = || { + let SStruct { b, .. } = x; + b + }; + + let _ = *r; +} + +fn match_tuple_struct(mut x: TStruct) { + let r = &mut x.0; + let _ = || { + let TStruct(_, a) = x; + a + }; + + let _ = *r; +} + +fn match_singleton(mut x: SSingle) { + let SSingle::A { a: ref mut r, .. } = x; + let _ = || { + let SSingle::A { b, .. } = x; + b + }; + + let _ = *r; +} + +fn match_tuple_singleton(mut x: TSingle) { + let TSingle::A(ref mut r, _) = x; + let _ = || { + let TSingle::A(_, a) = x; + a + }; + + let _ = *r; +} + +fn match_slice(x: (&[u32], u32, u32)) { + let _ = || { + let (([], a, _) | ([_, ..], _, a)) = x; + a + }; +} + +// Original testcase, for completeness +enum Camera { + Normal { base_transform: i32 }, + Volume { transform: i32 }, +} + +fn draw_ui(camera: &mut Camera) { + || { + let (Camera::Normal { + base_transform: _transform, + } + | Camera::Volume { + transform: _transform, + }) = camera; + }; +} + +fn draw_ui2(camera: &mut Camera) { + || { + let (Camera::Normal { + base_transform: _, + } + | Camera::Volume { + transform: _, + }) = camera; + }; +} + +fn main() {} diff --git a/tests/ui/coherence/coherence-cow.rs b/tests/ui/coherence/coherence-cow.rs index af94964762a95..2fc33e3a3e8f2 100644 --- a/tests/ui/coherence/coherence-cow.rs +++ b/tests/ui/coherence/coherence-cow.rs @@ -1,6 +1,6 @@ //@ revisions: re_a re_b re_c -#![cfg_attr(any(), re_a, re_b, re_c)] +#![cfg_attr(false, re_a, re_b, re_c)] //@ aux-build:coherence_lib.rs diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-false.rs b/tests/ui/conditional-compilation/cfg-attr-multi-false.rs index cfb430ec5b23a..871c1b81acd26 100644 --- a/tests/ui/conditional-compilation/cfg-attr-multi-false.rs +++ b/tests/ui/conditional-compilation/cfg-attr-multi-false.rs @@ -5,7 +5,7 @@ #![warn(unused_must_use)] -#[cfg_attr(any(), deprecated, must_use)] +#[cfg_attr(false, deprecated, must_use)] struct Struct {} impl Struct { diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-true.rs b/tests/ui/conditional-compilation/cfg-attr-multi-true.rs index 424760c2e663b..24950c8d42341 100644 --- a/tests/ui/conditional-compilation/cfg-attr-multi-true.rs +++ b/tests/ui/conditional-compilation/cfg-attr-multi-true.rs @@ -6,7 +6,7 @@ #![warn(unused_must_use)] -#[cfg_attr(all(), deprecated, must_use)] +#[cfg_attr(true, deprecated, must_use)] struct MustUseDeprecated {} impl MustUseDeprecated { //~ warning: use of deprecated diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.rs b/tests/ui/conditional-compilation/cfg-attr-parse.rs index b8aaad2685ef6..21df51264e2dc 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.rs +++ b/tests/ui/conditional-compilation/cfg-attr-parse.rs @@ -5,50 +5,50 @@ struct NoConfigurationPredicate; // Zero attributes, zero trailing comma (comma manatory here) -#[cfg_attr(all())] //~ error: expected `,`, found end of `cfg_attr` +#[cfg_attr(true)] //~ error: expected `,`, found end of `cfg_attr` struct A0C0; // Zero attributes, one trailing comma -#[cfg_attr(all(),)] +#[cfg_attr(true,)] //~^ WARN `#[cfg_attr]` does not expand to any attributes struct A0C1; // Zero attributes, two trailing commas -#[cfg_attr(all(),,)] //~ ERROR expected identifier +#[cfg_attr(true,,)] //~ ERROR expected identifier struct A0C2; // One attribute, no trailing comma -#[cfg_attr(all(), must_use)] // Ok +#[cfg_attr(true, must_use)] // Ok struct A1C0; // One attribute, one trailing comma -#[cfg_attr(all(), must_use,)] // Ok +#[cfg_attr(true, must_use,)] // Ok struct A1C1; // One attribute, two trailing commas -#[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier +#[cfg_attr(true, must_use,,)] //~ ERROR expected identifier struct A1C2; // Two attributes, no trailing comma -#[cfg_attr(all(), must_use, deprecated)] // Ok +#[cfg_attr(true, must_use, deprecated)] // Ok struct A2C0; // Two attributes, one trailing comma -#[cfg_attr(all(), must_use, deprecated,)] // Ok +#[cfg_attr(true, must_use, deprecated,)] // Ok struct A2C1; // Two attributes, two trailing commas -#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier +#[cfg_attr(true, must_use, deprecated,,)] //~ ERROR expected identifier struct A2C2; // Wrong delimiter `[` -#[cfg_attr[all(),,]] +#[cfg_attr[true,,]] //~^ ERROR wrong `cfg_attr` delimiters //~| ERROR expected identifier, found `,` struct BracketZero; // Wrong delimiter `{` -#[cfg_attr{all(),,}] +#[cfg_attr{true,,}] //~^ ERROR wrong `cfg_attr` delimiters //~| ERROR expected identifier, found `,` struct BraceZero; diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr index 4d4769b05cdaf..8dbe8969fd1c2 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr @@ -10,45 +10,45 @@ LL | #[cfg_attr()] = note: for more information, visit error: expected `,`, found end of `cfg_attr` input - --> $DIR/cfg-attr-parse.rs:8:17 + --> $DIR/cfg-attr-parse.rs:8:16 | -LL | #[cfg_attr(all())] - | ----------------^- - | | | - | | expected `,` +LL | #[cfg_attr(true)] + | ---------------^- + | | | + | | expected `,` | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:17:18 + --> $DIR/cfg-attr-parse.rs:17:17 | -LL | #[cfg_attr(all(),,)] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr(true,,)] + | ----------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:29:28 + --> $DIR/cfg-attr-parse.rs:29:27 | -LL | #[cfg_attr(all(), must_use,,)] - | ---------------------------^-- - | | | - | | expected identifier +LL | #[cfg_attr(true, must_use,,)] + | --------------------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:41:40 + --> $DIR/cfg-attr-parse.rs:41:39 | -LL | #[cfg_attr(all(), must_use, deprecated,,)] - | ---------------------------------------^-- - | | | - | | expected identifier +LL | #[cfg_attr(true, must_use, deprecated,,)] + | --------------------------------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -56,22 +56,22 @@ LL | #[cfg_attr(all(), must_use, deprecated,,)] error: wrong `cfg_attr` delimiters --> $DIR/cfg-attr-parse.rs:45:11 | -LL | #[cfg_attr[all(),,]] - | ^^^^^^^^^ +LL | #[cfg_attr[true,,]] + | ^^^^^^^^ | help: the delimiters should be `(` and `)` | -LL - #[cfg_attr[all(),,]] -LL + #[cfg_attr(all(),,)] +LL - #[cfg_attr[true,,]] +LL + #[cfg_attr(true,,)] | error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:45:18 + --> $DIR/cfg-attr-parse.rs:45:17 | -LL | #[cfg_attr[all(),,]] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr[true,,]] + | ----------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -79,22 +79,22 @@ LL | #[cfg_attr[all(),,]] error: wrong `cfg_attr` delimiters --> $DIR/cfg-attr-parse.rs:51:11 | -LL | #[cfg_attr{all(),,}] - | ^^^^^^^^^ +LL | #[cfg_attr{true,,}] + | ^^^^^^^^ | help: the delimiters should be `(` and `)` | -LL - #[cfg_attr{all(),,}] -LL + #[cfg_attr(all(),,)] +LL - #[cfg_attr{true,,}] +LL + #[cfg_attr(true,,)] | error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:51:18 + --> $DIR/cfg-attr-parse.rs:51:17 | -LL | #[cfg_attr{all(),,}] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr{true,,}] + | ----------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -102,8 +102,8 @@ LL | #[cfg_attr{all(),,}] warning: `#[cfg_attr]` does not expand to any attributes --> $DIR/cfg-attr-parse.rs:12:1 | -LL | #[cfg_attr(all(),)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true,)] + | ^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs index 45b757e928302..0305be5d24e65 100644 --- a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs +++ b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs @@ -1,6 +1,6 @@ macro_rules! foo { () => { - #[cfg_attr(all(), unknown)] + #[cfg_attr(true, unknown)] //~^ ERROR cannot find attribute `unknown` in this scope fn foo() {} } diff --git a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr index c91ad128d6e57..bdddbd68cdaf2 100644 --- a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr @@ -1,8 +1,8 @@ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27 + --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:26 | -LL | #[cfg_attr(all(), unknown)] - | ^^^^^^^ +LL | #[cfg_attr(true, unknown)] + | ^^^^^^^ ... LL | foo!(); | ------ in this macro invocation diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.rs b/tests/ui/conditional-compilation/cfg-empty-any-all.rs new file mode 100644 index 0000000000000..48ed4342235ca --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.rs @@ -0,0 +1,12 @@ +//! Test the behaviour of `cfg(any())` and `cfg(all())` + +#[cfg(any())] // Equivalent to cfg(false) +struct Disabled; + +#[cfg(all())] // Equivalent to cfg(true) +struct Enabled; + +fn main() { + let _ = Disabled; //~ ERROR: cannot find value `Disabled` + let _ = Enabled; // ok +} diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.stderr b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr new file mode 100644 index 0000000000000..1674f2def23a9 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find value `Disabled` in this scope + --> $DIR/cfg-empty-any-all.rs:10:13 + | +LL | let _ = Disabled; + | ^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/cfg-empty-any-all.rs:4:8 + | +LL | #[cfg(any())] // Equivalent to cfg(false) + | -- the item is gated here +LL | struct Disabled; + | ^^^^^^^^ +help: consider importing this unit variant + | +LL + use std::backtrace::BacktraceStatus::Disabled; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/conditional-compilation/cfg_attr_path.rs b/tests/ui/conditional-compilation/cfg_attr_path.rs index 00e07761977a8..f300e02932b73 100644 --- a/tests/ui/conditional-compilation/cfg_attr_path.rs +++ b/tests/ui/conditional-compilation/cfg_attr_path.rs @@ -3,8 +3,8 @@ #![deny(unused_attributes)] // c.f #35584 mod auxiliary { - #[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums; - #[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file; + #[cfg_attr(false, path = "nonexistent_file.rs")] pub mod namespaced_enums; + #[cfg_attr(true, path = "namespaced_enums.rs")] pub mod nonexistent_file; } fn main() { diff --git a/tests/ui/conditional-compilation/issue-34028.rs b/tests/ui/conditional-compilation/issue-34028.rs index 3ee43cb4b322d..d6f3f7a9abce5 100644 --- a/tests/ui/conditional-compilation/issue-34028.rs +++ b/tests/ui/conditional-compilation/issue-34028.rs @@ -1,7 +1,7 @@ //@ check-pass macro_rules! m { - () => { #[cfg(any())] fn f() {} } + () => { #[cfg(false)] fn f() {} } } trait T {} diff --git a/tests/ui/conditional-compilation/module_with_cfg.rs b/tests/ui/conditional-compilation/module_with_cfg.rs index a96f8a3e6e964..32486bdb43d68 100644 --- a/tests/ui/conditional-compilation/module_with_cfg.rs +++ b/tests/ui/conditional-compilation/module_with_cfg.rs @@ -1,3 +1,3 @@ //@ ignore-auxiliary (used by `./inner-cfg-non-inline-mod.rs`) -#![cfg_attr(all(), cfg(false))] +#![cfg_attr(true, cfg(false))] diff --git a/tests/ui/coroutine/static-closure-unexpanded.rs b/tests/ui/coroutine/static-closure-unexpanded.rs index 7cf24774deda0..ac7c251c83483 100644 --- a/tests/ui/coroutine/static-closure-unexpanded.rs +++ b/tests/ui/coroutine/static-closure-unexpanded.rs @@ -1,7 +1,7 @@ // Tests that static closures are not stable in the parser grammar unless the // coroutine feature is enabled. -#[cfg(any())] +#[cfg(false)] fn foo() { let _ = static || {}; //~^ ERROR coroutine syntax is experimental diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 7f669d0b93e5d..6cb4492c37544 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -58,7 +58,7 @@ fn patterns<'a>( ref pin const w: i32, //~ ERROR pinned reference syntax is experimental ) {} -#[cfg(any())] +#[cfg(false)] mod not_compiled { use std::pin::Pin; diff --git a/tests/ui/feature-gates/feature-gate-super-let.rs b/tests/ui/feature-gates/feature-gate-super-let.rs index 7be0800391338..19da1c4aa39bd 100644 --- a/tests/ui/feature-gates/feature-gate-super-let.rs +++ b/tests/ui/feature-gates/feature-gate-super-let.rs @@ -4,7 +4,7 @@ fn main() { } // Check that it also isn't accepted in cfg'd out code. -#[cfg(any())] +#[cfg(false)] fn a() { super let a = 1; //~^ ERROR `super let` is experimental diff --git a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs index a2997ced4fa1d..e1eda7def482f 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs @@ -1,4 +1,4 @@ -#[cfg(any())] +#[cfg(false)] fn test() { let x: unsafe<> (); //~^ ERROR unsafe binder types are experimental diff --git a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs index 8f9b411df4691..2b0bbaa083570 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs @@ -4,7 +4,7 @@ #![cfg_attr(with_gate, feature(unsafe_fields))] //[with_gate]~ WARNING -#[cfg(any())] +#[cfg(false)] struct Foo { unsafe field: (), //[without_gate]~ ERROR } @@ -12,14 +12,14 @@ struct Foo { // This should not parse as an unsafe field definition. struct FooTuple(unsafe fn()); -#[cfg(any())] +#[cfg(false)] enum Bar { Variant { unsafe field: () }, //[without_gate]~ ERROR // This should not parse as an unsafe field definition. VariantTuple(unsafe fn()), } -#[cfg(any())] +#[cfg(false)] union Baz { unsafe field: (), //[without_gate]~ ERROR } diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr b/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr index 6a8f01bbcce11..970763157d18c 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr @@ -21,8 +21,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:35:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -31,7 +31,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:36:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -61,8 +61,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:39:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -71,7 +71,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:40:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -101,8 +101,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:46:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -111,7 +111,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:47:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -141,8 +141,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:50:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -151,7 +151,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:51:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -181,8 +181,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:57:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -191,7 +191,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:58:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -221,8 +221,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:61:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -231,7 +231,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:62:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -261,8 +261,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:69:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -271,7 +271,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:70:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -301,8 +301,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:73:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -311,7 +311,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:74:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -341,8 +341,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:79:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -351,7 +351,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:80:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -381,8 +381,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:83:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -391,7 +391,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:84:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -421,8 +421,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:90:9 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -431,7 +431,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:91:9 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -461,8 +461,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:94:9 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -471,7 +471,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:95:9 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -501,8 +501,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:103:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -511,7 +511,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:104:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -541,8 +541,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:107:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -551,7 +551,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:108:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -581,8 +581,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:117:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -591,7 +591,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:118:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -621,8 +621,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:121:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -631,7 +631,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:122:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -661,8 +661,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:132:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -671,7 +671,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:133:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -701,8 +701,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:136:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -711,7 +711,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:137:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -741,8 +741,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:145:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -751,7 +751,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:146:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -781,8 +781,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:149:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -791,7 +791,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:150:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -821,8 +821,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:155:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -831,7 +831,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:156:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -861,8 +861,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:159:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -871,7 +871,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:160:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr b/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr index 6a8f01bbcce11..970763157d18c 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr @@ -21,8 +21,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:35:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -31,7 +31,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:36:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -61,8 +61,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:39:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -71,7 +71,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:40:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -101,8 +101,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:46:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -111,7 +111,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:47:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -141,8 +141,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:50:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -151,7 +151,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:51:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -181,8 +181,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:57:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -191,7 +191,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:58:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -221,8 +221,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:61:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -231,7 +231,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:62:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -261,8 +261,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:69:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -271,7 +271,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:70:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -301,8 +301,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:73:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -311,7 +311,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:74:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -341,8 +341,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:79:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -351,7 +351,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:80:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -381,8 +381,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:83:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -391,7 +391,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:84:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -421,8 +421,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:90:9 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -431,7 +431,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:91:9 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -461,8 +461,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:94:9 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -471,7 +471,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:95:9 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -501,8 +501,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:103:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -511,7 +511,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:104:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -541,8 +541,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:107:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -551,7 +551,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:108:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -581,8 +581,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:117:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -591,7 +591,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:118:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -621,8 +621,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:121:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -631,7 +631,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:122:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -661,8 +661,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:132:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -671,7 +671,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:133:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -701,8 +701,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:136:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -711,7 +711,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:137:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -741,8 +741,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:145:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -751,7 +751,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:146:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -781,8 +781,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:149:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -791,7 +791,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:150:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -821,8 +821,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:155:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -831,7 +831,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:156:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -861,8 +861,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:159:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -871,7 +871,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:160:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs b/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs index 09c734a52de04..b87a1d56ea060 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs @@ -15,16 +15,16 @@ trait TraitAA {} #[cfg_attr(b, cfg(b))] trait TraitBB {} -#[cfg(all())] +#[cfg(true)] trait TraitAll {} -#[cfg(any())] +#[cfg(false)] trait TraitAny {} -#[cfg_attr(all(), cfg(all()))] +#[cfg_attr(true, cfg(true))] trait TraitAllAll {} -#[cfg_attr(any(), cfg(any()))] +#[cfg_attr(false, cfg(false))] trait TraitAnyAny {} @@ -32,67 +32,67 @@ trait A where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { type B where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable fn foo(&self) where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable } impl A for T where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { type B = () where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable fn foo(&self) where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable {} } @@ -100,12 +100,12 @@ struct C where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { _t: PhantomData, } @@ -114,12 +114,12 @@ union D where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { _t: PhantomData, @@ -129,12 +129,12 @@ enum E where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { E(PhantomData), } @@ -142,21 +142,21 @@ where impl C where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { fn new() where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable {} } diff --git a/tests/ui/issues/issue-24434.rs b/tests/ui/issues/issue-24434.rs index 991084c274093..429bcf4a8d87d 100644 --- a/tests/ui/issues/issue-24434.rs +++ b/tests/ui/issues/issue-24434.rs @@ -1,6 +1,6 @@ //@ check-pass -#![cfg_attr(all(), feature(rustc_attrs))] +#![cfg_attr(true, feature(rustc_attrs))] #![rustc_dummy] fn main() {} diff --git a/tests/ui/lint/issue-97094.rs b/tests/ui/lint/issue-97094.rs index 22525ca11ae04..737f2827b67a6 100644 --- a/tests/ui/lint/issue-97094.rs +++ b/tests/ui/lint/issue-97094.rs @@ -2,19 +2,19 @@ // Ensure that unknown lints inside cfg-attr's are linted for -#![cfg_attr(all(), allow(nonex_lint_top_level))] +#![cfg_attr(true, allow(nonex_lint_top_level))] //~^ ERROR unknown lint -#![cfg_attr(all(), allow(bare_trait_object))] +#![cfg_attr(true, allow(bare_trait_object))] //~^ ERROR has been renamed -#[cfg_attr(all(), allow(nonex_lint_mod))] +#[cfg_attr(true, allow(nonex_lint_mod))] //~^ ERROR unknown lint mod baz { - #![cfg_attr(all(), allow(nonex_lint_mod_inner))] + #![cfg_attr(true, allow(nonex_lint_mod_inner))] //~^ ERROR unknown lint } -#[cfg_attr(all(), allow(nonex_lint_fn))] +#[cfg_attr(true, allow(nonex_lint_fn))] //~^ ERROR unknown lint pub fn main() {} @@ -25,24 +25,24 @@ macro_rules! bar { } bar!( - #[cfg_attr(all(), allow(nonex_lint_in_macro))] + #[cfg_attr(true, allow(nonex_lint_in_macro))] //~^ ERROR unknown lint pub fn _bar() {} ); // No warning for non-applying cfg -#[cfg_attr(any(), allow(nonex_lint_fn))] +#[cfg_attr(false, allow(nonex_lint_fn))] pub fn _foo() {} // Allowing unknown lints works if inside cfg_attr -#[cfg_attr(all(), allow(unknown_lints))] +#[cfg_attr(true, allow(unknown_lints))] mod bar_allowed { #[allow(nonex_lint_fn)] fn _foo() {} } // ... but not if the cfg_attr doesn't evaluate -#[cfg_attr(any(), allow(unknown_lints))] +#[cfg_attr(false, allow(unknown_lints))] mod bar_not_allowed { #[allow(nonex_lint_fn)] //~^ ERROR unknown lint diff --git a/tests/ui/lint/issue-97094.stderr b/tests/ui/lint/issue-97094.stderr index 1a0a3eaf25077..e12250aa7542e 100644 --- a/tests/ui/lint/issue-97094.stderr +++ b/tests/ui/lint/issue-97094.stderr @@ -1,8 +1,8 @@ error: unknown lint: `nonex_lint_top_level` - --> $DIR/issue-97094.rs:5:26 + --> $DIR/issue-97094.rs:5:25 | -LL | #![cfg_attr(all(), allow(nonex_lint_top_level))] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(true, allow(nonex_lint_top_level))] + | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/issue-97094.rs:1:9 @@ -12,36 +12,36 @@ LL | #![deny(warnings)] = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]` error: lint `bare_trait_object` has been renamed to `bare_trait_objects` - --> $DIR/issue-97094.rs:7:26 + --> $DIR/issue-97094.rs:7:25 | -LL | #![cfg_attr(all(), allow(bare_trait_object))] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` +LL | #![cfg_attr(true, allow(bare_trait_object))] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` | = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]` error: unknown lint: `nonex_lint_mod` - --> $DIR/issue-97094.rs:10:25 + --> $DIR/issue-97094.rs:10:24 | -LL | #[cfg_attr(all(), allow(nonex_lint_mod))] - | ^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_mod))] + | ^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_mod_inner` - --> $DIR/issue-97094.rs:13:30 + --> $DIR/issue-97094.rs:13:29 | -LL | #![cfg_attr(all(), allow(nonex_lint_mod_inner))] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(true, allow(nonex_lint_mod_inner))] + | ^^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:17:25 + --> $DIR/issue-97094.rs:17:24 | -LL | #[cfg_attr(all(), allow(nonex_lint_fn))] - | ^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_fn))] + | ^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_in_macro` - --> $DIR/issue-97094.rs:28:29 + --> $DIR/issue-97094.rs:28:28 | -LL | #[cfg_attr(all(), allow(nonex_lint_in_macro))] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_in_macro))] + | ^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` --> $DIR/issue-97094.rs:47:13 diff --git a/tests/ui/macros/issue-34171.rs b/tests/ui/macros/issue-34171.rs index fbc2ea50097da..3f13341230fa8 100644 --- a/tests/ui/macros/issue-34171.rs +++ b/tests/ui/macros/issue-34171.rs @@ -6,5 +6,5 @@ macro_rules! apply_null { } fn main() { - apply_null!(#[cfg(all())] fn f() {}); + apply_null!(#[cfg(true)] fn f() {}); } diff --git a/tests/ui/parser/attribute-on-empty.rs b/tests/ui/parser/attribute-on-empty.rs index 5932377f73eca..0177e6c1b59d4 100644 --- a/tests/ui/parser/attribute-on-empty.rs +++ b/tests/ui/parser/attribute-on-empty.rs @@ -4,7 +4,7 @@ struct Baz(i32); fn main() { - let _: Baz<#[cfg(any())]> = todo!(); + let _: Baz<#[cfg(false)]> = todo!(); //~^ ERROR attributes cannot be applied here } diff --git a/tests/ui/parser/attribute-on-empty.stderr b/tests/ui/parser/attribute-on-empty.stderr index 7c4806c8704aa..6bcbf1ceb8d1f 100644 --- a/tests/ui/parser/attribute-on-empty.stderr +++ b/tests/ui/parser/attribute-on-empty.stderr @@ -1,7 +1,7 @@ error: attributes cannot be applied here --> $DIR/attribute-on-empty.rs:7:16 | -LL | let _: Baz<#[cfg(any())]> = todo!(); +LL | let _: Baz<#[cfg(false)]> = todo!(); | - ^^^^^^^^^^^^^ attributes are not allowed here | | | while parsing the type for `_` diff --git a/tests/ui/parser/attribute-on-type.rs b/tests/ui/parser/attribute-on-type.rs index 196d322bdf8f3..b400bd1c173f0 100644 --- a/tests/ui/parser/attribute-on-type.rs +++ b/tests/ui/parser/attribute-on-type.rs @@ -16,16 +16,16 @@ fn main() { let _: #[attr] &'static str = "123"; //~^ ERROR attributes cannot be applied to types - let _: Bar<#[cfg(any())] 'static> = Bar(&123); + let _: Bar<#[cfg(false)] 'static> = Bar(&123); //~^ ERROR attributes cannot be applied to generic arguments - let _: Baz<#[cfg(any())] 42> = Baz(42); + let _: Baz<#[cfg(false)] 42> = Baz(42); //~^ ERROR attributes cannot be applied to generic arguments let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new()); //~^ ERROR attributes cannot be applied to generic arguments - let _: Bar<#[cfg(any())] 'static> = Bar(&456); + let _: Bar<#[cfg(false)] 'static> = Bar(&456); //~^ ERROR attributes cannot be applied to generic arguments let _generic: Box<#[attr] i32> = Box::new(1); diff --git a/tests/ui/parser/attribute-on-type.stderr b/tests/ui/parser/attribute-on-type.stderr index 603c7e2be51a0..316620325c04c 100644 --- a/tests/ui/parser/attribute-on-type.stderr +++ b/tests/ui/parser/attribute-on-type.stderr @@ -13,13 +13,13 @@ LL | let _: #[attr] &'static str = "123"; error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:19:16 | -LL | let _: Bar<#[cfg(any())] 'static> = Bar(&123); +LL | let _: Bar<#[cfg(false)] 'static> = Bar(&123); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:22:16 | -LL | let _: Baz<#[cfg(any())] 42> = Baz(42); +LL | let _: Baz<#[cfg(false)] 42> = Baz(42); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments @@ -31,7 +31,7 @@ LL | let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new()); error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:28:16 | -LL | let _: Bar<#[cfg(any())] 'static> = Bar(&456); +LL | let _: Bar<#[cfg(false)] 'static> = Bar(&456); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments diff --git a/tests/ui/parser/attribute/attr-pat-struct-rest.rs b/tests/ui/parser/attribute/attr-pat-struct-rest.rs index b2bfcf82df8d1..8f0e4cd827e09 100644 --- a/tests/ui/parser/attribute/attr-pat-struct-rest.rs +++ b/tests/ui/parser/attribute/attr-pat-struct-rest.rs @@ -3,6 +3,6 @@ struct S {} fn main() { - let S { #[cfg(any())] .. } = S {}; + let S { #[cfg(false)] .. } = S {}; //~^ ERROR expected identifier, found `..` } diff --git a/tests/ui/parser/attribute/attr-pat-struct-rest.stderr b/tests/ui/parser/attribute/attr-pat-struct-rest.stderr index f72c54973fce7..94ad7d5711015 100644 --- a/tests/ui/parser/attribute/attr-pat-struct-rest.stderr +++ b/tests/ui/parser/attribute/attr-pat-struct-rest.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `..` --> $DIR/attr-pat-struct-rest.rs:6:27 | -LL | let S { #[cfg(any())] .. } = S {}; +LL | let S { #[cfg(false)] .. } = S {}; | - ^^ expected identifier | | | while parsing the fields for this pattern diff --git a/tests/ui/parser/cfg-keyword-lifetime.rs b/tests/ui/parser/cfg-keyword-lifetime.rs index a1588eddc0747..c61b69175c880 100644 --- a/tests/ui/parser/cfg-keyword-lifetime.rs +++ b/tests/ui/parser/cfg-keyword-lifetime.rs @@ -1,6 +1,6 @@ // Disallow `'keyword` even in cfg'd code. -#[cfg(any())] +#[cfg(false)] fn hello() -> &'ref () {} //~^ ERROR lifetimes cannot use keyword names diff --git a/tests/ui/parser/issue-116781.rs b/tests/ui/parser/issue-116781.rs index 0e951d2eaa448..176350fe2eec6 100644 --- a/tests/ui/parser/issue-116781.rs +++ b/tests/ui/parser/issue-116781.rs @@ -1,6 +1,6 @@ #[derive(Debug)] struct Foo { - #[cfg(all())] + #[cfg(true)] field: fn(($),), //~ ERROR expected pattern, found `$` //~^ ERROR expected pattern, found `$` } diff --git a/tests/ui/parser/raw/raw-idents.rs b/tests/ui/parser/raw/raw-idents.rs index 93015ee6c4942..4e1e6b124c311 100644 --- a/tests/ui/parser/raw/raw-idents.rs +++ b/tests/ui/parser/raw/raw-idents.rs @@ -62,7 +62,7 @@ macro_rules! tests { impl<$kw> B<$kw> {} } mod extern_crate { - #[cfg(any())] + #[cfg(false)] extern crate $kw; } mod body { diff --git a/tests/ui/parser/ty-path-followed-by-single-colon.rs b/tests/ui/parser/ty-path-followed-by-single-colon.rs index a9082ea317a78..588fec3f2fc8f 100644 --- a/tests/ui/parser/ty-path-followed-by-single-colon.rs +++ b/tests/ui/parser/ty-path-followed-by-single-colon.rs @@ -12,7 +12,7 @@ mod garden { fn g(_: impl Take) {} // OK! - #[cfg(any())] fn h() where a::path:to::nowhere {} // OK! + #[cfg(false)] fn h() where a::path:to::nowhere {} // OK! fn i(_: impl Take:to::somewhere>) {} // OK! diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs index 63d3c79055ca2..e36a12beb8182 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs @@ -9,7 +9,7 @@ use builtin_attrs::{bench, test}; #[repr(C)] //~ ERROR `repr` is ambiguous struct S; -#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous +#[cfg_attr(true, repr(C))] //~ ERROR `repr` is ambiguous struct SCond; #[test] // OK, shadowed diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr index ff7894a41eab0..d057019862604 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -20,10 +20,10 @@ LL | use builtin_attrs::*; = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:12:19 + --> $DIR/ambiguous-builtin-attrs.rs:12:18 | -LL | #[cfg_attr(all(), repr(C))] - | ^^^^ ambiguous name +LL | #[cfg_attr(true, repr(C))] + | ^^^^ ambiguous name | = note: ambiguous because of a name conflict with a builtin attribute = note: `repr` could refer to a built-in attribute diff --git a/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs b/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs index cb60c182a43c2..b1da93de2a6e9 100644 --- a/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs +++ b/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs @@ -4,6 +4,6 @@ use proc_macro::TokenStream; #[proc_macro_derive(Foo, attributes(foo))] pub fn derive(input: TokenStream) -> TokenStream { - assert!(!input.to_string().contains("#[cfg(any())]")); + assert!(!input.to_string().contains("#[cfg(false)]")); "".parse().unwrap() } diff --git a/tests/ui/proc-macro/cfg-eval.rs b/tests/ui/proc-macro/cfg-eval.rs index 9e9e469125883..60c94ad2a7523 100644 --- a/tests/ui/proc-macro/cfg-eval.rs +++ b/tests/ui/proc-macro/cfg-eval.rs @@ -17,9 +17,9 @@ extern crate test_macros; struct S1 { #[cfg(false)] field_false: u8, - #[cfg(all(/*true*/))] + #[cfg(true)] #[cfg_attr(FALSE, unknown_attr)] - #[cfg_attr(all(/*true*/), allow())] //~ WARN unused attribute + #[cfg_attr(true, allow())] //~ WARN unused attribute field_true: u8, } @@ -29,9 +29,9 @@ struct S2 {} fn main() { // Subtle - we need a trailing comma after the '1' - otherwise, `#[cfg_eval]` will - // turn this into `(#[cfg(all())] 1)`, which is a parenthesized expression, not a tuple + // turn this into `(#[cfg(true)] 1)`, which is a parenthesized expression, not a tuple // expression. `#[cfg]` is not supported inside parenthesized expressions, so this will // produce an error when attribute collection runs. let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)] - (#[cfg(false)] 0, #[cfg(all(/*true*/))] 1,); + (#[cfg(false)] 0, #[cfg(true)] 1,); } diff --git a/tests/ui/proc-macro/cfg-eval.stderr b/tests/ui/proc-macro/cfg-eval.stderr index 1429dbde7bfc2..72c452c7a08a1 100644 --- a/tests/ui/proc-macro/cfg-eval.stderr +++ b/tests/ui/proc-macro/cfg-eval.stderr @@ -1,8 +1,8 @@ warning: unused attribute --> $DIR/cfg-eval.rs:22:5 | -LL | #[cfg_attr(all(/*true*/), allow())] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute +LL | #[cfg_attr(true, allow())] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `allow` with an empty list has no effect = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/proc-macro/cfg-eval.stdout b/tests/ui/proc-macro/cfg-eval.stdout index 5d88297ad6880..6493eee465476 100644 --- a/tests/ui/proc-macro/cfg-eval.stdout +++ b/tests/ui/proc-macro/cfg-eval.stdout @@ -1,5 +1,5 @@ -PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true: u8, } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true : u8, } +PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(true)] #[allow()] field_true: u8, } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct S1 { #[cfg(true)] #[allow()] field_true : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -28,19 +28,14 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "all", - span: $DIR/cfg-eval.rs:20:11: 20:14 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/cfg-eval.rs:20:14: 20:24 (#0), + ident: "true", + span: $DIR/cfg-eval.rs:20:11: 20:15 (#0), }, ], - span: $DIR/cfg-eval.rs:20:10: 20:25 (#0), + span: $DIR/cfg-eval.rs:20:10: 20:16 (#0), }, ], - span: $DIR/cfg-eval.rs:20:6: 20:26 (#0), + span: $DIR/cfg-eval.rs:20:6: 20:17 (#0), }, Punct { ch: '#', @@ -52,15 +47,15 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "allow", - span: $DIR/cfg-eval.rs:22:31: 22:36 (#0), + span: $DIR/cfg-eval.rs:22:22: 22:27 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/cfg-eval.rs:22:36: 22:38 (#0), + span: $DIR/cfg-eval.rs:22:27: 22:29 (#0), }, ], - span: $DIR/cfg-eval.rs:22:6: 22:40 (#0), + span: $DIR/cfg-eval.rs:22:6: 22:31 (#0), }, Ident { ident: "field_true", @@ -84,7 +79,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval.rs:17:11: 24:2 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] (#[cfg(all())] 1,) +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] (#[cfg(true)] 1,) PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -120,32 +115,27 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "all", - span: $DIR/cfg-eval.rs:36:29: 36:32 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/cfg-eval.rs:36:32: 36:42 (#0), + ident: "true", + span: $DIR/cfg-eval.rs:36:29: 36:33 (#0), }, ], - span: $DIR/cfg-eval.rs:36:28: 36:43 (#0), + span: $DIR/cfg-eval.rs:36:28: 36:34 (#0), }, ], - span: $DIR/cfg-eval.rs:36:24: 36:44 (#0), + span: $DIR/cfg-eval.rs:36:24: 36:35 (#0), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/cfg-eval.rs:36:45: 36:46 (#0), + span: $DIR/cfg-eval.rs:36:36: 36:37 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/cfg-eval.rs:36:46: 36:47 (#0), + span: $DIR/cfg-eval.rs:36:37: 36:38 (#0), }, ], - span: $DIR/cfg-eval.rs:36:5: 36:48 (#0), + span: $DIR/cfg-eval.rs:36:5: 36:39 (#0), }, ] diff --git a/tests/ui/proc-macro/derive-attr-cfg.rs b/tests/ui/proc-macro/derive-attr-cfg.rs index 2f3516cabae9e..21d3a93ffa6cd 100644 --- a/tests/ui/proc-macro/derive-attr-cfg.rs +++ b/tests/ui/proc-macro/derive-attr-cfg.rs @@ -9,7 +9,7 @@ use derive_attr_cfg::Foo; #[derive(Foo)] #[foo] struct S { - #[cfg(any())] + #[cfg(false)] x: i32 } diff --git a/tests/ui/proc-macro/derive-b.rs b/tests/ui/proc-macro/derive-b.rs index 68d341478f187..c04152f629caa 100644 --- a/tests/ui/proc-macro/derive-b.rs +++ b/tests/ui/proc-macro/derive-b.rs @@ -4,7 +4,7 @@ extern crate derive_b_rpass as derive_b; #[derive(Debug, PartialEq, derive_b::B, Eq, Copy, Clone)] -#[cfg_attr(all(), B[arbitrary tokens])] +#[cfg_attr(true, B[arbitrary tokens])] struct B { #[C] a: u64 diff --git a/tests/ui/proc-macro/derive-helper-configured.rs b/tests/ui/proc-macro/derive-helper-configured.rs index b753e29b8bf3b..b96ebdebaebb9 100644 --- a/tests/ui/proc-macro/derive-helper-configured.rs +++ b/tests/ui/proc-macro/derive-helper-configured.rs @@ -7,9 +7,9 @@ extern crate test_macros; #[derive(Empty)] -#[cfg_attr(all(), empty_helper)] +#[cfg_attr(true, empty_helper)] struct S { - #[cfg_attr(all(), empty_helper)] + #[cfg_attr(true, empty_helper)] field: u8, } diff --git a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed index cfbf9ef386843..f6fbff175a997 100644 --- a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed +++ b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed @@ -3,7 +3,7 @@ //@ compile-flags: -Aunused use y::z; -#[cfg(all())] +#[cfg(true)] use y::Whatever; mod y { diff --git a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs index 98be104d8fde6..73f263e19aa41 100644 --- a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs +++ b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs @@ -2,7 +2,7 @@ //@ run-rustfix //@ compile-flags: -Aunused -#[cfg(all())] +#[cfg(true)] use y::Whatever; mod y { diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed index a2f04daa4b859..c1adc90161a46 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed @@ -43,7 +43,7 @@ macro_rules! meta2 { macro_rules! with_cfg_attr { () => { - #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] + #[cfg_attr(true, unsafe(link_section = ".custom_section"))] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs index 88c9328fd9cd5..9fdf379046345 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs @@ -43,7 +43,7 @@ macro_rules! meta2 { macro_rules! with_cfg_attr { () => { - #[cfg_attr(all(), link_section = ".custom_section")] + #[cfg_attr(true, link_section = ".custom_section")] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr index 55df60c51d9cd..279e61a9cb673 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr @@ -77,10 +77,10 @@ LL | #[unsafe($e = $l)] | +++++++ + error: unsafe attribute used without unsafe - --> $DIR/unsafe-attributes-fix.rs:46:27 + --> $DIR/unsafe-attributes-fix.rs:46:26 | -LL | #[cfg_attr(all(), link_section = ".custom_section")] - | ^^^^^^^^^^^^ usage of unsafe attribute +LL | #[cfg_attr(true, link_section = ".custom_section")] + | ^^^^^^^^^^^^ usage of unsafe attribute ... LL | with_cfg_attr!(); | ---------------- in this macro invocation @@ -90,8 +90,8 @@ LL | with_cfg_attr!(); = note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info) help: wrap the attribute in `unsafe(...)` | -LL | #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] - | +++++++ + +LL | #[cfg_attr(true, unsafe(link_section = ".custom_section"))] + | +++++++ + error: unsafe attribute used without unsafe --> $DIR/unsafe-attributes-fix.rs:67:3 diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs index e2db7c01adf29..c1c9f79996ed1 100644 --- a/tests/ui/static/static-align.rs +++ b/tests/ui/static/static-align.rs @@ -53,7 +53,7 @@ thread_local! { #[allow(unused_mut, reason = "test attribute handling")] #[cfg_attr(TRUE, cfg_attr(FOURTY_TWO = "42", - cfg_attr(all(), + cfg_attr(true, cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096))))))] #[allow(unused_mut, reason = "test attribute handling")] diff --git a/tests/ui/structs/struct-field-cfg.rs b/tests/ui/structs/struct-field-cfg.rs index 42cab8ab916bb..84f913927dab5 100644 --- a/tests/ui/structs/struct-field-cfg.rs +++ b/tests/ui/structs/struct-field-cfg.rs @@ -3,16 +3,16 @@ struct Foo { } fn main() { - let foo = Foo { #[cfg(all())] present: () }; - let _ = Foo { #[cfg(any())] present: () }; + let foo = Foo { #[cfg(true)] present: () }; + let _ = Foo { #[cfg(false)] present: () }; //~^ ERROR missing field `present` in initializer of `Foo` - let _ = Foo { present: (), #[cfg(any())] absent: () }; - let _ = Foo { present: (), #[cfg(all())] absent: () }; + let _ = Foo { present: (), #[cfg(false)] absent: () }; + let _ = Foo { present: (), #[cfg(true)] absent: () }; //~^ ERROR struct `Foo` has no field named `absent` - let Foo { #[cfg(all())] present: () } = foo; - let Foo { #[cfg(any())] present: () } = foo; + let Foo { #[cfg(true)] present: () } = foo; + let Foo { #[cfg(false)] present: () } = foo; //~^ ERROR pattern does not mention field `present` - let Foo { present: (), #[cfg(any())] absent: () } = foo; - let Foo { present: (), #[cfg(all())] absent: () } = foo; + let Foo { present: (), #[cfg(false)] absent: () } = foo; + let Foo { present: (), #[cfg(true)] absent: () } = foo; //~^ ERROR struct `Foo` does not have a field named `absent` } diff --git a/tests/ui/structs/struct-field-cfg.stderr b/tests/ui/structs/struct-field-cfg.stderr index 2bca6f302db72..db280a632d63f 100644 --- a/tests/ui/structs/struct-field-cfg.stderr +++ b/tests/ui/structs/struct-field-cfg.stderr @@ -1,44 +1,44 @@ error[E0063]: missing field `present` in initializer of `Foo` --> $DIR/struct-field-cfg.rs:7:13 | -LL | let _ = Foo { #[cfg(any())] present: () }; +LL | let _ = Foo { #[cfg(false)] present: () }; | ^^^ missing `present` error[E0560]: struct `Foo` has no field named `absent` - --> $DIR/struct-field-cfg.rs:10:46 + --> $DIR/struct-field-cfg.rs:10:45 | -LL | let _ = Foo { present: (), #[cfg(all())] absent: () }; - | ^^^^^^ `Foo` does not have this field +LL | let _ = Foo { present: (), #[cfg(true)] absent: () }; + | ^^^^^^ `Foo` does not have this field | = note: all struct fields are already assigned error[E0027]: pattern does not mention field `present` --> $DIR/struct-field-cfg.rs:13:9 | -LL | let Foo { #[cfg(any())] present: () } = foo; +LL | let Foo { #[cfg(false)] present: () } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present` | help: include the missing field in the pattern | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { present } = foo; | help: if you don't care about this missing field, you can explicitly ignore it | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { present: _ } = foo; | help: or always ignore missing fields here | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { .. } = foo; | error[E0026]: struct `Foo` does not have a field named `absent` - --> $DIR/struct-field-cfg.rs:16:42 + --> $DIR/struct-field-cfg.rs:16:41 | -LL | let Foo { present: (), #[cfg(all())] absent: () } = foo; - | ^^^^^^ struct `Foo` does not have this field +LL | let Foo { present: (), #[cfg(true)] absent: () } = foo; + | ^^^^^^ struct `Foo` does not have this field error: aborting due to 4 previous errors diff --git a/tests/ui/test-attrs/issue-34932.rs b/tests/ui/test-attrs/issue-34932.rs index feb6556b60a12..f0cbdd07df84c 100644 --- a/tests/ui/test-attrs/issue-34932.rs +++ b/tests/ui/test-attrs/issue-34932.rs @@ -1,6 +1,6 @@ //@ run-pass //@ compile-flags:--test -#![cfg(any())] // This test should be configured away +#![cfg(false)] // This test should be configured away #![feature(rustc_attrs)] // Test that this is allowed on stable/beta #![feature(iter_arith_traits)] // Test that this is not unused #![deny(unused_features)] diff --git a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs index 7f0f6a214aae9..383d9108eb908 100644 --- a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs +++ b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs @@ -23,15 +23,6 @@ fn upvar() { }; } -fn enum_upvar() { - type T = impl Copy; - let foo: T = Some((1u32, 2u32)); - let x = move || match foo { - None => (), - Some((a, b)) => (), - }; -} - fn r#struct() { #[derive(Copy, Clone)] struct Foo((u32, u32)); diff --git a/tests/ui/typeck/issue-86721-return-expr-ice.rs b/tests/ui/typeck/issue-86721-return-expr-ice.rs index ea3a2f2fbfe6e..ed36164aea606 100644 --- a/tests/ui/typeck/issue-86721-return-expr-ice.rs +++ b/tests/ui/typeck/issue-86721-return-expr-ice.rs @@ -1,7 +1,7 @@ // Regression test for the ICE described in #86721. //@ revisions: rev1 rev2 -#![cfg_attr(any(), rev1, rev2)] +#![cfg_attr(false, rev1, rev2)] #![crate_type = "lib"] #[cfg(any(rev1))] diff --git a/triagebot.toml b/triagebot.toml index 397e6875eef9f..3182122bdeb06 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1154,7 +1154,7 @@ cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] [mentions."compiler/rustc_public"] message = "This PR changes rustc_public" -cc = ["@oli-obk", "@celinval", "@ouz-a"] +cc = ["@oli-obk", "@celinval", "@ouz-a", "@makai410"] [mentions."compiler/rustc_target/src/spec"] message = """ @@ -1542,6 +1542,7 @@ project-stable-mir = [ "@celinval", "@oli-obk", "@scottmcm", + "@makai410", ] project-exploit-mitigations = [ "@cuviper",