diff options
628 files changed, 7598 insertions, 3077 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0d37e8b2f84..6be3bced5e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -443,20 +443,6 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform 0.1.9", - "semver", - "serde", - "serde_json", - "thiserror 2.0.12", -] - -[[package]] -name = "cargo_metadata" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cfca2aaa699835ba88faf58a06342a314a950d2b9686165e038286c30316868" @@ -1364,7 +1350,7 @@ version = "0.1.0" dependencies = [ "anyhow", "askama", - "cargo_metadata 0.18.1", + "cargo_metadata 0.21.0", "serde", "serde_json", "thiserror 1.0.69", @@ -4255,6 +4241,7 @@ dependencies = [ "rustc-literal-escaper", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -5369,7 +5356,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "build_helper", - "cargo_metadata 0.19.2", + "cargo_metadata 0.21.0", "fluent-syntax", "ignore", "miropt-test-tools", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 97e07095875..984b280e81b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2849,7 +2849,7 @@ impl InlineAsmOperand { } } -#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] +#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic, Walkable, PartialEq, Eq)] pub enum AsmMacro { /// The `asm!` macro Asm, diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 1e2576bef2c..610c93a253c 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -416,12 +416,24 @@ pub enum AttributeKind { /// Represents `#[pointee]` Pointee(Span), + /// Represents `#[proc_macro]` + ProcMacro(Span), + + /// Represents `#[proc_macro_attribute]` + ProcMacroAttribute(Span), + + /// Represents `#[proc_macro_derive]` + ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span }, + /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). PubTransparent(Span), /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span }, + /// Represents `#[rustc_builtin_macro]`. + RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span }, + /// Represents `#[rustc_layout_scalar_valid_range_end]`. RustcLayoutScalarValidRangeEnd(Box<u128>, Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 159b807a3b2..af2d46d0bc7 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -61,8 +61,12 @@ impl AttributeKind { PassByValue(..) => Yes, Path(..) => No, Pointee(..) => No, + ProcMacro(..) => No, + ProcMacroAttribute(..) => No, + ProcMacroDerive { .. } => No, PubTransparent(..) => Yes, Repr { .. } => No, + RustcBuiltinMacro { .. } => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 15b90bd2ed7..0c10517d044 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -41,6 +41,7 @@ pub(crate) mod must_use; pub(crate) mod no_implicit_prelude; pub(crate) mod non_exhaustive; pub(crate) mod path; +pub(crate) mod proc_macro_attrs; pub(crate) mod repr; pub(crate) mod rustc_internal; pub(crate) mod semantics; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs new file mode 100644 index 00000000000..4de77dc268e --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -0,0 +1,139 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; + +use crate::attributes::{ + AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, +}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct ProcMacroParser; +impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser { + const PATH: &[Symbol] = &[sym::proc_macro]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro; +} + +pub(crate) struct ProcMacroAttributeParser; +impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser { + const PATH: &[Symbol] = &[sym::proc_macro_attribute]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute; +} + +pub(crate) struct ProcMacroDeriveParser; +impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser { + const PATH: &[Symbol] = &[sym::proc_macro_derive]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = + template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + 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"), + helper_attrs, + span: cx.attr_span, + }) + } +} + +pub(crate) struct RustcBuiltinMacroParser; +impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser { + const PATH: &[Symbol] = &[sym::rustc_builtin_macro]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = + template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?; + Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span }) + } +} + +fn parse_derive_like<S: Stage>( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, + trait_name_mandatory: bool, +) -> Option<(Option<Symbol>, ThinVec<Symbol>)> { + let Some(list) = args.list() else { + // For #[rustc_builtin_macro], it is permitted to leave out the trait name + if args.no_args().is_ok() && !trait_name_mandatory { + return Some((None, ThinVec::new())); + } + cx.expected_list(cx.attr_span); + return None; + }; + let mut items = list.mixed(); + + // Parse the name of the trait that is derived. + let Some(trait_attr) = items.next() else { + cx.expected_at_least_one_argument(list.span); + return None; + }; + let Some(trait_attr) = trait_attr.meta_item() else { + cx.unexpected_literal(trait_attr.span()); + return None; + }; + let Some(trait_ident) = trait_attr.path().word() else { + cx.expected_identifier(trait_attr.path().span()); + return None; + }; + if !trait_ident.name.can_be_raw() { + cx.expected_identifier(trait_ident.span); + return None; + } + if let Err(e) = trait_attr.args().no_args() { + cx.expected_no_args(e); + return None; + }; + + // Parse optional attributes + let mut attributes = ThinVec::new(); + if let Some(attrs) = items.next() { + let Some(attr_list) = attrs.meta_item() else { + cx.expected_list(attrs.span()); + return None; + }; + if !attr_list.path().word_is(sym::attributes) { + cx.expected_specific_argument(attrs.span(), vec!["attributes"]); + return None; + } + let Some(attr_list) = attr_list.args().list() else { + cx.expected_list(attrs.span()); + return None; + }; + + // Parse item in `attributes(...)` argument + for attr in attr_list.mixed() { + let Some(attr) = attr.meta_item() else { + cx.expected_identifier(attr.span()); + return None; + }; + if let Err(e) = attr.args().no_args() { + cx.expected_no_args(e); + return None; + }; + let Some(ident) = attr.path().word() else { + cx.expected_identifier(attr.path().span()); + return None; + }; + if !ident.name.can_be_raw() { + cx.expected_identifier(ident.span); + return None; + } + attributes.push(ident.name); + } + } + + // If anything else is specified, we should reject it + if let Some(next) = items.next() { + cx.expected_no_args(next.span()); + } + + Some((Some(trait_ident.name), attributes)) +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 45bfe345207..9b86d101840 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -38,6 +38,9 @@ use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::non_exhaustive::NonExhaustiveParser; use crate::attributes::path::PathParser as PathAttributeParser; +use crate::attributes::proc_macro_attrs::{ + ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser, +}; use crate::attributes::repr::{AlignParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, @@ -154,6 +157,8 @@ attribute_parsers!( Single<MustUseParser>, Single<OptimizeParser>, Single<PathAttributeParser>, + Single<ProcMacroDeriveParser>, + Single<RustcBuiltinMacroParser>, Single<RustcForceInlineParser>, Single<RustcLayoutScalarValidRangeEnd>, Single<RustcLayoutScalarValidRangeStart>, @@ -186,6 +191,8 @@ attribute_parsers!( Single<WithoutArgs<ParenSugarParser>>, Single<WithoutArgs<PassByValueParser>>, Single<WithoutArgs<PointeeParser>>, + Single<WithoutArgs<ProcMacroAttributeParser>>, + Single<WithoutArgs<ProcMacroParser>>, Single<WithoutArgs<PubTransparentParser>>, Single<WithoutArgs<SpecializationTraitParser>>, Single<WithoutArgs<StdInternalSymbolParser>>, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 040a0607db5..7031a9bb3d4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1290,6 +1290,58 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { span, format!("if `{ty}` implemented `Clone`, you could clone the value"), ); + } else if let ty::Adt(_, _) = ty.kind() + && let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait() + { + // For cases like `Option<NonClone>`, where `Option<T>: Clone` if `T: Clone`, we point + // at the types that should be `Clone`. + let ocx = ObligationCtxt::new_with_diagnostics(self.infcx); + let cause = ObligationCause::misc(expr.span, self.mir_def_id()); + ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait); + let errors = ocx.select_all_or_error(); + if errors.iter().all(|error| { + match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) { + Some(clause) => match clause.self_ty().skip_binder().kind() { + ty::Adt(def, _) => def.did().is_local() && clause.def_id() == clone_trait, + _ => false, + }, + None => false, + } + }) { + let mut type_spans = vec![]; + let mut types = FxIndexSet::default(); + for clause in errors + .iter() + .filter_map(|e| e.obligation.predicate.as_clause()) + .filter_map(|c| c.as_trait_clause()) + { + let ty::Adt(def, _) = clause.self_ty().skip_binder().kind() else { continue }; + type_spans.push(self.infcx.tcx.def_span(def.did())); + types.insert( + self.infcx + .tcx + .short_string(clause.self_ty().skip_binder(), &mut err.long_ty_path()), + ); + } + let mut span: MultiSpan = type_spans.clone().into(); + for sp in type_spans { + span.push_span_label(sp, "consider implementing `Clone` for this type"); + } + span.push_span_label(expr.span, "you could clone this value"); + let types: Vec<_> = types.into_iter().collect(); + let msg = match &types[..] { + [only] => format!("`{only}`"), + [head @ .., last] => format!( + "{} and `{last}`", + head.iter().map(|t| format!("`{t}`")).collect::<Vec<_>>().join(", ") + ), + [] => unreachable!(), + }; + err.span_note( + span, + format!("if {msg} implemented `Clone`, you could clone the value"), + ); + } } } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 42b7e0e06d1..09f5e6f6efc 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,11 +1,13 @@ -use std::mem; +use std::{mem, slice}; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, NodeId, attr}; +use rustc_ast::{self as ast, HasNodeId, NodeId, attr}; use rustc_ast_pretty::pprust; +use rustc_attr_data_structures::AttributeKind; +use rustc_attr_parsing::AttributeParser; use rustc_errors::DiagCtxtHandle; -use rustc_expand::base::{ExtCtxt, ResolverExpand, parse_macro_name_and_helper_attrs}; +use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; use rustc_session::Session; @@ -22,7 +24,7 @@ struct ProcMacroDerive { trait_name: Symbol, function_ident: Ident, span: Span, - attrs: Vec<Symbol>, + attrs: ThinVec<Symbol>, } struct ProcMacroDef { @@ -41,6 +43,7 @@ struct CollectProcMacros<'a> { macros: Vec<ProcMacro>, in_root: bool, dcx: DiagCtxtHandle<'a>, + session: &'a Session, source_map: &'a SourceMap, is_proc_macro_crate: bool, is_test_crate: bool, @@ -63,6 +66,7 @@ pub fn inject( macros: Vec::new(), in_root: true, dcx, + session: sess, source_map: sess.source_map(), is_proc_macro_crate, is_test_crate, @@ -98,8 +102,18 @@ impl<'a> CollectProcMacros<'a> { function_ident: Ident, attr: &'a ast::Attribute, ) { - let Some((trait_name, proc_attrs)) = - parse_macro_name_and_helper_attrs(self.dcx, attr, "derive") + let Some(rustc_hir::Attribute::Parsed(AttributeKind::ProcMacroDerive { + trait_name, + helper_attrs, + .. + })) = AttributeParser::parse_limited( + self.session, + slice::from_ref(attr), + sym::proc_macro_derive, + item.span, + item.node_id(), + None, + ) else { return; }; @@ -110,7 +124,7 @@ impl<'a> CollectProcMacros<'a> { span: item.span, trait_name, function_ident, - attrs: proc_attrs, + attrs: helper_attrs, })); } else { let msg = if !self.in_root { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs index 574463be7ff..39a59560c9d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs @@ -39,10 +39,7 @@ impl Coords { /// or other expansions), and if it does happen then skipping a span or function is /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option<Coords> { - if span.is_empty() { - debug_assert!(false, "can't make coords from empty span: {span:?}"); - return None; - } + let span = ensure_non_empty_span(source_map, span)?; let lo = span.lo(); let hi = span.hi(); @@ -73,6 +70,29 @@ pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) }) } +fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> { + if !span.is_empty() { + return Some(span); + } + + // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'. + source_map + .span_to_source(span, |src, start, end| try { + // Adjusting span endpoints by `BytePos(1)` is normally a bug, + // but in this case we have specifically checked that the character + // we're skipping over is one of two specific ASCII characters, so + // adjusting by exactly 1 byte is correct. + if src.as_bytes().get(end).copied() == Some(b'{') { + Some(span.with_hi(span.hi() + BytePos(1))) + } else if start > 0 && src.as_bytes()[start - 1] == b'}' { + Some(span.with_lo(span.lo() - BytePos(1))) + } else { + None + } + }) + .ok()? +} + /// If `llvm-cov` sees a source region that is improperly ordered (end < start), /// it will immediately exit with a fatal error. To prevent that from happening, /// discard regions that are improperly ordered, or might be interpreted in a diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index fcc0d378f06..7b27e496986 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -382,26 +382,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let width = size.bits(); let llty = self.type_ix(width); match name { - sym::ctlz | sym::cttz => { - let y = self.const_bool(false); - let ret = self.call_intrinsic( - format!("llvm.{name}"), - &[llty], - &[args[0].immediate(), y], - ); - - self.intcast(ret, result.layout.llvm_type(self), false) - } - sym::ctlz_nonzero => { - let y = self.const_bool(true); - let ret = - self.call_intrinsic("llvm.ctlz", &[llty], &[args[0].immediate(), y]); - self.intcast(ret, result.layout.llvm_type(self), false) - } - sym::cttz_nonzero => { - let y = self.const_bool(true); + sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => { + let y = + self.const_bool(name == sym::ctlz_nonzero || name == sym::cttz_nonzero); + let llvm_name = if name == sym::ctlz || name == sym::ctlz_nonzero { + "llvm.ctlz" + } else { + "llvm.cttz" + }; let ret = - self.call_intrinsic("llvm.cttz", &[llty], &[args[0].immediate(), y]); + self.call_intrinsic(llvm_name, &[llty], &[args[0].immediate(), y]); self.intcast(ret, result.layout.llvm_type(self), false) } sym::ctpop => { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 0fb987bdf82..53899da183a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -405,6 +405,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { ("mips64" | "mips64r6", _) => false, // Selection bug <https://github.com/llvm/llvm-project/issues/95471> ("nvptx64", _) => false, + // Unsupported https://github.com/llvm/llvm-project/issues/121122 + ("amdgpu", _) => false, // ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full // list at <https://github.com/rust-lang/rust/issues/116909>) ("powerpc" | "powerpc64", _) => false, @@ -433,6 +435,9 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86` // (ld is 80-bit extended precision). + // + // musl does not implement the symbols required for f128 math at all. + _ if target_env == "musl" => false, ("x86_64", _) => false, (_, "linux") if target_pointer_width == 64 => true, _ => false, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index dd49db26689..3f456fa115a 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -511,15 +511,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { err.emit(); } - // Any linkage to LLVM intrinsics for now forcibly marks them all as never - // unwinds since LLVM sometimes can't handle codegen which `invoke`s - // intrinsic functions. - if let Some(name) = &codegen_fn_attrs.link_name - && name.as_str().starts_with("llvm.") - { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; - } - if let Some(features) = check_tied_features( tcx.sess, &codegen_fn_attrs diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 6d6465dd798..c2c023af090 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -1,12 +1,13 @@ //! An analysis to determine which locals require allocas and //! which do not. +use rustc_abi as abi; use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::DenseBitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::{bug, span_bug}; use tracing::debug; @@ -99,63 +100,75 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> context: PlaceContext, location: Location, ) { - let cx = self.fx.cx; - - if let Some((place_base, elem)) = place_ref.last_projection() { - let mut base_context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - - // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = matches!( - context, - PlaceContext::NonMutatingUse( - NonMutatingUseContext::Copy | NonMutatingUseContext::Move, - ) - ); - if is_consume { - let base_ty = place_base.ty(self.fx.mir, cx.tcx()); - let base_ty = self.fx.monomorphize(base_ty); - - // ZSTs don't require any actual memory access. - let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty; - let span = self.fx.mir.local_decls[place_ref.local].source_info.span; - if cx.spanned_layout_of(elem_ty, span).is_zst() { - return; + if !place_ref.projection.is_empty() { + const COPY_CONTEXT: PlaceContext = + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); + + // `PlaceElem::Index` is the only variant that can mention other `Local`s, + // so check for those up-front before any potential short-circuits. + for elem in place_ref.projection { + if let mir::PlaceElem::Index(index_local) = *elem { + self.visit_local(index_local, COPY_CONTEXT, location); } + } - if let mir::ProjectionElem::Field(..) = elem { - let layout = cx.spanned_layout_of(base_ty.ty, span); - if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { - // Recurse with the same context, instead of `Projection`, - // potentially stopping at non-operand projections, - // which would trigger `not_ssa` on locals. - base_context = context; - } - } + // If our local is already memory, nothing can make it *more* memory + // so we don't need to bother checking the projections further. + if self.locals[place_ref.local] == LocalKind::Memory { + return; } - if let mir::ProjectionElem::Deref = elem { - // Deref projections typically only read the pointer. - base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); + if place_ref.is_indirect_first_projection() { + // If this starts with a `Deref`, we only need to record a read of the + // pointer being dereferenced, as all the subsequent projections are + // working on a place which is always supported. (And because we're + // looking at codegen MIR, it can only happen as the first projection.) + self.visit_local(place_ref.local, COPY_CONTEXT, location); + return; } - self.process_place(&place_base, base_context, location); - // HACK(eddyb) this emulates the old `visit_projection_elem`, this - // entire `visit_place`-like `process_place` method should be rewritten, - // now that we have moved to the "slice of projections" representation. - if let mir::ProjectionElem::Index(local) = elem { - self.visit_local( - local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location, - ); + if context.is_mutating_use() { + // If it's a mutating use it doesn't matter what the projections are, + // if there are *any* then we need a place to write. (For example, + // `_1 = Foo()` works in SSA but `_2.0 = Foo()` does not.) + let mut_projection = PlaceContext::MutatingUse(MutatingUseContext::Projection); + self.visit_local(place_ref.local, mut_projection, location); + return; } - } else { - self.visit_local(place_ref.local, context, location); + + // Scan through to ensure the only projections are those which + // `FunctionCx::maybe_codegen_consume_direct` can handle. + let base_ty = self.fx.monomorphized_place_ty(mir::PlaceRef::from(place_ref.local)); + let mut layout = self.fx.cx.layout_of(base_ty); + for elem in place_ref.projection { + layout = match *elem { + mir::PlaceElem::Field(fidx, ..) => layout.field(self.fx.cx, fidx.as_usize()), + mir::PlaceElem::Downcast(_, vidx) + if let abi::Variants::Single { index: single_variant } = + layout.variants + && vidx == single_variant => + { + layout.for_variant(self.fx.cx, vidx) + } + mir::PlaceElem::Subtype(subtype_ty) => { + let subtype_ty = self.fx.monomorphize(subtype_ty); + self.fx.cx.layout_of(subtype_ty) + } + _ => { + self.locals[place_ref.local] = LocalKind::Memory; + return; + } + } + } + debug_assert!( + !self.fx.cx.is_backend_ref(layout), + "Post-projection {place_ref:?} layout should be non-Ref, but it's {layout:?}", + ); } + + // Even with supported projections, we still need to have `visit_local` + // check for things that can't be done in SSA (like `SharedBorrow`). + self.visit_local(place_ref.local, context, location); } } @@ -170,11 +183,6 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer if let Some(local) = place.as_local() { self.define(local, DefLocation::Assignment(location)); - if self.locals[local] != LocalKind::Memory { - if !self.fx.rvalue_creates_operand(rvalue) { - self.locals[local] = LocalKind::Memory; - } - } } else { self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location); } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 8e308aac769..5459f95c186 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -335,13 +335,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let val = if field.is_zst() { OperandValue::ZeroSized - } else if let BackendRepr::SimdVector { .. } = self.layout.backend_repr { - // codegen_transmute_operand doesn't support SIMD, but since the previous - // check handled ZSTs, the only possible field access into something SIMD - // is to the `non_1zst_field` that's the same SIMD. (Other things, even - // just padding, would change the wrapper's representation type.) - assert_eq!(field.size, self.layout.size); - self.val } else if field.size == self.layout.size { assert_eq!(offset.bytes(), 0); fx.codegen_transmute_operand(bx, *self, field) @@ -928,9 +921,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match self.locals[place_ref.local] { LocalRef::Operand(mut o) => { - // Moves out of scalar and scalar pair fields are trivial. - for elem in place_ref.projection.iter() { - match elem { + // We only need to handle the projections that + // `LocalAnalyzer::process_place` let make it here. + for elem in place_ref.projection { + match *elem { mir::ProjectionElem::Field(f, _) => { assert!( !o.layout.ty.is_any_ptr(), @@ -939,17 +933,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); o = o.extract_field(self, bx, f.index()); } - mir::ProjectionElem::Index(_) - | mir::ProjectionElem::ConstantIndex { .. } => { - // ZSTs don't require any actual memory access. - // FIXME(eddyb) deduplicate this with the identical - // checks in `codegen_consume` and `extract_field`. - let elem = o.layout.field(bx.cx(), 0); - if elem.is_zst() { - o = OperandRef::zero_sized(elem); - } else { - return None; - } + mir::PlaceElem::Downcast(_, vidx) => { + debug_assert_eq!( + o.layout.variants, + abi::Variants::Single { index: vidx }, + ); + let layout = o.layout.for_variant(bx.cx(), vidx); + o = OperandRef { val: o.val, layout } + } + mir::PlaceElem::Subtype(subtype_ty) => { + let subtype_ty = self.monomorphize(subtype_ty); + let layout = self.cx.layout_of(subtype_ty); + o = OperandRef { val: o.val, layout } } _ => return None, } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index a5759b79be4..8a67b8d6e5f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -2,12 +2,12 @@ use rustc_abi::{self as abi, FIRST_VARIANT}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_middle::{bug, mir}; +use rustc_middle::{bug, mir, span_bug}; use rustc_session::config::OptLevel; use tracing::{debug, instrument}; use super::operand::{OperandRef, OperandRefBuilder, OperandValue}; -use super::place::{PlaceRef, codegen_tag_value}; +use super::place::{PlaceRef, PlaceValue, codegen_tag_value}; use super::{FunctionCx, LocalRef}; use crate::common::{IntPredicate, TypeKind}; use crate::traits::*; @@ -180,7 +180,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { - assert!(self.rvalue_creates_operand(rvalue)); let temp = self.codegen_rvalue_operand(bx, rvalue); temp.val.store(bx, dest); } @@ -218,17 +217,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// Transmutes an `OperandValue` to another `OperandValue`. /// - /// This is supported only for cases where [`Self::rvalue_creates_operand`] - /// returns `true`, and will ICE otherwise. (In particular, anything that - /// would need to `alloca` in order to return a `PlaceValue` will ICE, - /// expecting those to go via [`Self::codegen_transmute`] instead where - /// the destination place is already allocated.) + /// This is supported for all cases where the `cast` type is SSA, + /// but for non-ZSTs with [`abi::BackendRepr::Memory`] it ICEs. pub(crate) fn codegen_transmute_operand( &mut self, bx: &mut Bx, operand: OperandRef<'tcx, Bx::Value>, cast: TyAndLayout<'tcx>, ) -> OperandValue<Bx::Value> { + if let abi::BackendRepr::Memory { .. } = cast.backend_repr + && !cast.is_zst() + { + span_bug!(self.mir.span, "Use `codegen_transmute` to transmute to {cast:?}"); + } + + // `Layout` is interned, so we can do a cheap check for things that are + // exactly the same and thus don't need any handling. + if abi::Layout::eq(&operand.layout.layout, &cast.layout) { + return operand.val; + } + // Check for transmutes that are always UB. if operand.layout.size != cast.size || operand.layout.is_uninhabited() @@ -241,11 +249,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return OperandValue::poison(bx, cast); } + // To or from pointers takes different methods, so we use this to restrict + // the SimdVector case to types which can be `bitcast` between each other. + #[inline] + fn vector_can_bitcast(x: abi::Scalar) -> bool { + matches!( + x, + abi::Scalar::Initialized { + value: abi::Primitive::Int(..) | abi::Primitive::Float(..), + .. + } + ) + } + + let cx = bx.cx(); match (operand.val, operand.layout.backend_repr, cast.backend_repr) { _ if cast.is_zst() => OperandValue::ZeroSized, - (_, _, abi::BackendRepr::Memory { .. }) => { - bug!("Cannot `codegen_transmute_operand` to non-ZST memory-ABI output {cast:?}"); - } (OperandValue::Ref(source_place_val), abi::BackendRepr::Memory { .. }, _) => { assert_eq!(source_place_val.llextra, None); // The existing alignment is part of `source_place_val`, @@ -256,16 +275,46 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Immediate(imm), abi::BackendRepr::Scalar(from_scalar), abi::BackendRepr::Scalar(to_scalar), - ) => OperandValue::Immediate(transmute_scalar(bx, imm, from_scalar, to_scalar)), + ) if from_scalar.size(cx) == to_scalar.size(cx) => { + OperandValue::Immediate(transmute_scalar(bx, imm, from_scalar, to_scalar)) + } + ( + OperandValue::Immediate(imm), + abi::BackendRepr::SimdVector { element: from_scalar, .. }, + abi::BackendRepr::SimdVector { element: to_scalar, .. }, + ) if vector_can_bitcast(from_scalar) && vector_can_bitcast(to_scalar) => { + let to_backend_ty = bx.cx().immediate_backend_type(cast); + OperandValue::Immediate(bx.bitcast(imm, to_backend_ty)) + } ( OperandValue::Pair(imm_a, imm_b), abi::BackendRepr::ScalarPair(in_a, in_b), abi::BackendRepr::ScalarPair(out_a, out_b), - ) => OperandValue::Pair( - transmute_scalar(bx, imm_a, in_a, out_a), - transmute_scalar(bx, imm_b, in_b, out_b), - ), - _ => bug!("Cannot `codegen_transmute_operand` {operand:?} to {cast:?}"), + ) if in_a.size(cx) == out_a.size(cx) && in_b.size(cx) == out_b.size(cx) => { + OperandValue::Pair( + transmute_scalar(bx, imm_a, in_a, out_a), + transmute_scalar(bx, imm_b, in_b, out_b), + ) + } + _ => { + // For any other potentially-tricky cases, make a temporary instead. + // If anything else wants the target local to be in memory this won't + // be hit, as `codegen_transmute` will get called directly. Thus this + // is only for places where everything else wants the operand form, + // and thus it's not worth making those places get it from memory. + // + // Notably, Scalar ⇌ ScalarPair cases go here to avoid padding + // and endianness issues, as do SimdVector ones to avoid worrying + // about things like f32x8 ⇌ ptrx4 that would need multiple steps. + let align = Ord::max(operand.layout.align.abi, cast.align.abi); + let size = Ord::max(operand.layout.size, cast.size); + let temp = PlaceValue::alloca(bx, size, align); + bx.lifetime_start(temp.llval, size); + operand.val.store(bx, temp.with_type(operand.layout)); + let val = bx.load_operand(temp.with_type(cast)).val; + bx.lifetime_end(temp.llval, size); + val + } } } @@ -326,8 +375,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, rvalue: &mir::Rvalue<'tcx>, ) -> OperandRef<'tcx, Bx::Value> { - assert!(self.rvalue_creates_operand(rvalue), "cannot codegen {rvalue:?} to operand",); - match *rvalue { mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { let operand = self.codegen_operand(bx, source); @@ -653,8 +700,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = self.monomorphize(ty); let layout = self.cx.layout_of(ty); - // `rvalue_creates_operand` has arranged that we only get here if - // we can build the aggregate immediate from the field immediates. let mut builder = OperandRefBuilder::new(layout); for (field_idx, field) in fields.iter_enumerated() { let op = self.codegen_operand(bx, field); @@ -955,69 +1000,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Pair(val, of) } - - /// Returns `true` if the `rvalue` can be computed into an [`OperandRef`], - /// rather than needing a full `PlaceRef` for the assignment destination. - /// - /// This is used by the [`super::analyze`] code to decide which MIR locals - /// can stay as SSA values (as opposed to generating `alloca` slots for them). - /// As such, some paths here return `true` even where the specific rvalue - /// will not actually take the operand path because the result type is such - /// that it always gets an `alloca`, but where it's not worth re-checking the - /// layout in this code when the right thing will happen anyway. - pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { - match *rvalue { - mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.mir, self.cx.tcx()); - let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty)); - let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty)); - match (operand_layout.backend_repr, cast_layout.backend_repr) { - // When the output will be in memory anyway, just use its place - // (instead of the operand path) unless it's the trivial ZST case. - (_, abi::BackendRepr::Memory { .. }) => cast_layout.is_zst(), - - // Otherwise (for a non-memory output) if the input is memory - // then we can just read the value from the place. - (abi::BackendRepr::Memory { .. }, _) => true, - - // When we have scalar immediates, we can only convert things - // where the sizes match, to avoid endianness questions. - (abi::BackendRepr::Scalar(a), abi::BackendRepr::Scalar(b)) => - a.size(self.cx) == b.size(self.cx), - (abi::BackendRepr::ScalarPair(a0, a1), abi::BackendRepr::ScalarPair(b0, b1)) => - a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx), - - // Mixing Scalars and ScalarPairs can get quite complicated when - // padding and undef get involved, so leave that to the memory path. - (abi::BackendRepr::Scalar(_), abi::BackendRepr::ScalarPair(_, _)) | - (abi::BackendRepr::ScalarPair(_, _), abi::BackendRepr::Scalar(_)) => false, - - // SIMD vectors aren't worth the trouble of dealing with complex - // cases like from vectors of f32 to vectors of pointers or - // from fat pointers to vectors of u16. (See #143194 #110021 ...) - (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false, - } - } - mir::Rvalue::Ref(..) | - mir::Rvalue::CopyForDeref(..) | - mir::Rvalue::RawPtr(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::ShallowInitBox(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::NullaryOp(..) | - mir::Rvalue::ThreadLocalRef(_) | - mir::Rvalue::Use(..) | - mir::Rvalue::Repeat(..) | // (*) - mir::Rvalue::Aggregate(..) | // (*) - mir::Rvalue::WrapUnsafeBinder(..) => // (*) - true, - } - - // (*) this is only true if the type is suitable - } } /// Transmutes a single scalar value `imm` from `from_scalar` to `to_scalar`. diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index aa0bc42d448..2985eafb63a 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -128,15 +128,15 @@ const_eval_frame_note_inner = inside {$where_ -> const_eval_frame_note_last = the failure occurred here +const_eval_incompatible_arg_types = + calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty} + const_eval_incompatible_calling_conventions = calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}" const_eval_incompatible_return_types = calling a function with return type {$callee_ty} passing return place of type {$caller_ty} -const_eval_incompatible_types = - calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} - const_eval_interior_mutable_borrow_escaping = interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed .label = this borrow of an interior mutable value refers to such a temporary diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index b6a64035261..a4148cb145f 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -500,7 +500,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { InvalidNichedEnumVariantWritten { .. } => { const_eval_invalid_niched_enum_variant_written } - AbiMismatchArgument { .. } => const_eval_incompatible_types, + AbiMismatchArgument { .. } => const_eval_incompatible_arg_types, AbiMismatchReturn { .. } => const_eval_incompatible_return_types, } } @@ -625,12 +625,16 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("data_size", info.data_size); } InvalidNichedEnumVariantWritten { enum_ty } => { - diag.arg("ty", enum_ty.to_string()); + diag.arg("ty", enum_ty); } - AbiMismatchArgument { caller_ty, callee_ty } - | AbiMismatchReturn { caller_ty, callee_ty } => { - diag.arg("caller_ty", caller_ty.to_string()); - diag.arg("callee_ty", callee_ty.to_string()); + AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => { + diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output + diag.arg("caller_ty", caller_ty); + diag.arg("callee_ty", callee_ty); + } + AbiMismatchReturn { caller_ty, callee_ty } => { + diag.arg("caller_ty", caller_ty); + diag.arg("callee_ty", callee_ty); } } } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 1503f3bcd99..bda00ea2fb8 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -270,6 +270,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), >, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, + callee_arg_idx: usize, callee_arg: &mir::Place<'tcx>, callee_ty: Ty<'tcx>, already_live: bool, @@ -298,6 +299,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Check compatibility if !self.check_argument_compat(caller_abi, callee_abi)? { throw_ub!(AbiMismatchArgument { + arg_idx: callee_arg_idx, caller_ty: caller_abi.layout.ty, callee_ty: callee_abi.layout.ty }); @@ -424,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // this is a single iterator (that handles `spread_arg`), then // `pass_argument` would be the loop body. It takes care to // not advance `caller_iter` for ignored arguments. - let mut callee_args_abis = callee_fn_abi.args.iter(); + let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); for local in body.args_iter() { // Construct the destination place for this argument. At this point all // locals are still dead, so we cannot construct a `PlaceTy`. @@ -445,10 +447,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], *self.tcx, ); - let callee_abi = callee_args_abis.next().unwrap(); + let (idx, callee_abi) = callee_args_abis.next().unwrap(); self.pass_argument( &mut caller_args, callee_abi, + idx, &dest, field_ty, /* already_live */ true, @@ -456,10 +459,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } else { // Normal argument. Cannot mark it as live yet, it might be unsized! - let callee_abi = callee_args_abis.next().unwrap(); + let (idx, callee_abi) = callee_args_abis.next().unwrap(); self.pass_argument( &mut caller_args, callee_abi, + idx, &dest, ty, /* already_live */ false, diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 881aa679156..4a9551a60cf 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -551,6 +551,11 @@ impl SelfProfilerRef { pub fn get_self_profiler(&self) -> Option<Arc<SelfProfiler>> { self.profiler.clone() } + + /// Is expensive recording of query keys and/or function arguments enabled? + pub fn is_args_recording_enabled(&self) -> bool { + self.enabled() && self.event_filter_mask.intersects(EventFilter::ARGS) + } } /// A helper for recording costly arguments to self-profiling events. Used with diff --git a/compiler/rustc_errors/src/markdown/term.rs b/compiler/rustc_errors/src/markdown/term.rs index 579e00b8b85..fe1d80bdbe8 100644 --- a/compiler/rustc_errors/src/markdown/term.rs +++ b/compiler/rustc_errors/src/markdown/term.rs @@ -18,7 +18,7 @@ thread_local! { pub(crate) fn entrypoint(stream: &MdStream<'_>, buf: &mut Buffer) -> io::Result<()> { #[cfg(not(test))] if let Some((w, _)) = termize::dimensions() { - WIDTH.with(|c| c.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH))); + WIDTH.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH)); } write_stream(stream, buf, None, 0)?; buf.write_all(b"\n") @@ -84,7 +84,7 @@ fn write_tt(tt: &MdTree<'_>, buf: &mut Buffer, indent: usize) -> io::Result<()> reset_cursor(); } MdTree::HorizontalRule => { - (0..WIDTH.with(Cell::get)).for_each(|_| buf.write_all(b"-").unwrap()); + (0..WIDTH.get()).for_each(|_| buf.write_all(b"-").unwrap()); reset_cursor(); } MdTree::Heading(n, stream) => { @@ -121,7 +121,7 @@ fn write_tt(tt: &MdTree<'_>, buf: &mut Buffer, indent: usize) -> io::Result<()> /// End of that block, just wrap the line fn reset_cursor() { - CURSOR.with(|cur| cur.set(0)); + CURSOR.set(0); } /// Change to be generic on Write for testing. If we have a link URL, we don't @@ -144,7 +144,7 @@ fn write_wrapping<B: io::Write>( buf.write_all(ind_ws)?; cur.set(indent); } - let ch_count = WIDTH.with(Cell::get) - cur.get(); + let ch_count = WIDTH.get() - cur.get(); let mut iter = to_write.char_indices(); let Some((end_idx, _ch)) = iter.nth(ch_count) else { // Write entire line diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 89d6e62834d..5a53670c865 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -1,26 +1,8 @@ -expand_arg_not_attributes = - second argument must be `attributes` - -expand_attr_no_arguments = - attribute must have either one or two arguments - -expand_attribute_meta_item = - attribute must be a meta item, not a literal - -expand_attribute_single_word = - attribute must only be a single word - expand_attributes_on_expressions_experimental = attributes on expressions are experimental .help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//` .help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !` -expand_attributes_wrong_form = - attribute must be of form: `attributes(foo, bar)` - -expand_cannot_be_name_of_macro = - `{$trait_ident}` cannot be a name of {$macro_type} macro - expand_collapse_debuginfo_illegal = illegal value for attribute #[collapse_debuginfo(no|external|yes)] @@ -71,9 +53,6 @@ expand_glob_delegation_outside_impls = expand_glob_delegation_traitless_qpath = qualified path without a trait in glob delegation -expand_helper_attribute_name_invalid = - `{$name}` cannot be a name of derive helper attribute - expand_incomplete_parse = macro expansion ignores {$descr} and any tokens following .label = caused by the macro expansion here @@ -165,12 +144,6 @@ expand_mve_unrecognized_var = expand_non_inline_modules_in_proc_macro_input_are_unstable = non-inline modules in proc macro input are unstable -expand_not_a_meta_item = - not a meta item - -expand_only_one_word = - must only be one word - expand_proc_macro_back_compat = using an old version of `{$crate_name}` .note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 25ec5401111..c01320fc644 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -861,7 +861,7 @@ impl SyntaxExtension { /// | (unspecified) | no | if-ext | if-ext | yes | /// | external | no | if-ext | if-ext | yes | /// | yes | yes | yes | yes | yes | - fn get_collapse_debuginfo(sess: &Session, attrs: &[impl AttributeExt], ext: bool) -> bool { + fn get_collapse_debuginfo(sess: &Session, attrs: &[hir::Attribute], ext: bool) -> bool { let flag = sess.opts.cg.collapse_macro_debuginfo; let attr = ast::attr::find_by_name(attrs, sym::collapse_debuginfo) .and_then(|attr| { @@ -872,7 +872,7 @@ impl SyntaxExtension { .ok() }) .unwrap_or_else(|| { - if ast::attr::contains_name(attrs, sym::rustc_builtin_macro) { + if find_attr!(attrs, AttributeKind::RustcBuiltinMacro { .. }) { CollapseMacroDebuginfo::Yes } else { CollapseMacroDebuginfo::Unspecified @@ -915,16 +915,18 @@ impl SyntaxExtension { let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local); tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); - let (builtin_name, helper_attrs) = ast::attr::find_by_name(attrs, sym::rustc_builtin_macro) - .map(|attr| { - // Override `helper_attrs` passed above if it's a built-in macro, - // marking `proc_macro_derive` macros as built-in is not a realistic use case. - parse_macro_name_and_helper_attrs(sess.dcx(), attr, "built-in").map_or_else( - || (Some(name), Vec::new()), - |(name, helper_attrs)| (Some(name), helper_attrs), - ) - }) - .unwrap_or_else(|| (None, helper_attrs)); + let (builtin_name, helper_attrs) = match find_attr!(attrs, AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, .. } => (builtin_name, helper_attrs)) + { + // Override `helper_attrs` passed above if it's a built-in macro, + // marking `proc_macro_derive` macros as built-in is not a realistic use case. + Some((Some(name), helper_attrs)) => { + (Some(*name), helper_attrs.iter().copied().collect()) + } + Some((None, _)) => (Some(name), Vec::new()), + + // Not a built-in macro + None => (None, helper_attrs), + }; let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability); @@ -1141,7 +1143,7 @@ pub trait ResolverExpand { /// Names of specific methods to which glob delegation expands. fn glob_delegation_suffixes( - &mut self, + &self, trait_def_id: DefId, impl_def_id: LocalDefId, ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>; @@ -1224,6 +1226,7 @@ pub struct ExtCtxt<'a> { pub(super) expanded_inert_attrs: MarkedAttrs, /// `-Zmacro-stats` data. pub macro_stats: FxHashMap<(Symbol, MacroKind), MacroStat>, + pub nb_macro_errors: usize, } impl<'a> ExtCtxt<'a> { @@ -1254,6 +1257,7 @@ impl<'a> ExtCtxt<'a> { expanded_inert_attrs: MarkedAttrs::new(), buffered_early_lint: vec![], macro_stats: Default::default(), + nb_macro_errors: 0, } } @@ -1315,6 +1319,12 @@ impl<'a> ExtCtxt<'a> { self.current_expansion.id.expansion_cause() } + /// This method increases the internal macro errors count and then call `trace_macros_diag`. + pub fn macro_error_and_trace_macros_diag(&mut self) { + self.nb_macro_errors += 1; + self.trace_macros_diag(); + } + pub fn trace_macros_diag(&mut self) { for (span, notes) in self.expansions.iter() { let mut db = self.dcx().create_note(errors::TraceMacro { span: *span }); @@ -1382,80 +1392,6 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe } } -pub fn parse_macro_name_and_helper_attrs( - dcx: DiagCtxtHandle<'_>, - attr: &impl AttributeExt, - macro_type: &str, -) -> Option<(Symbol, Vec<Symbol>)> { - // Once we've located the `#[proc_macro_derive]` attribute, verify - // that it's of the form `#[proc_macro_derive(Foo)]` or - // `#[proc_macro_derive(Foo, attributes(A, ..))]` - let list = attr.meta_item_list()?; - let ([trait_attr] | [trait_attr, _]) = list.as_slice() else { - dcx.emit_err(errors::AttrNoArguments { span: attr.span() }); - return None; - }; - let Some(trait_attr) = trait_attr.meta_item() else { - dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() }); - return None; - }; - let trait_ident = match trait_attr.ident() { - Some(trait_ident) if trait_attr.is_word() => trait_ident, - _ => { - dcx.emit_err(errors::OnlyOneWord { span: trait_attr.span }); - return None; - } - }; - - if !trait_ident.name.can_be_raw() { - dcx.emit_err(errors::CannotBeNameOfMacro { - span: trait_attr.span, - trait_ident, - macro_type, - }); - } - - let attributes_attr = list.get(1); - let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { - if !attr.has_name(sym::attributes) { - dcx.emit_err(errors::ArgumentNotAttributes { span: attr.span() }); - } - attr.meta_item_list() - .unwrap_or_else(|| { - dcx.emit_err(errors::AttributesWrongForm { span: attr.span() }); - &[] - }) - .iter() - .filter_map(|attr| { - let Some(attr) = attr.meta_item() else { - dcx.emit_err(errors::AttributeMetaItem { span: attr.span() }); - return None; - }; - - let ident = match attr.ident() { - Some(ident) if attr.is_word() => ident, - _ => { - dcx.emit_err(errors::AttributeSingleWord { span: attr.span }); - return None; - } - }; - if !ident.name.can_be_raw() { - dcx.emit_err(errors::HelperAttributeNameInvalid { - span: attr.span, - name: ident, - }); - } - - Some(ident.name) - }) - .collect() - } else { - Vec::new() - }; - - Some((trait_ident.name, proc_attrs)) -} - /// If this item looks like a specific enums from `rental`, emit a fatal error. /// See #73345 and #83125 for more details. /// FIXME(#73933): Remove this eventually. diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 3ac5d213053..fd1391a554a 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -79,72 +79,6 @@ pub(crate) struct MacroBodyStability { } #[derive(Diagnostic)] -#[diag(expand_attr_no_arguments)] -pub(crate) struct AttrNoArguments { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_not_a_meta_item)] -pub(crate) struct NotAMetaItem { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_only_one_word)] -pub(crate) struct OnlyOneWord { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_cannot_be_name_of_macro)] -pub(crate) struct CannotBeNameOfMacro<'a> { - #[primary_span] - pub span: Span, - pub trait_ident: Ident, - pub macro_type: &'a str, -} - -#[derive(Diagnostic)] -#[diag(expand_arg_not_attributes)] -pub(crate) struct ArgumentNotAttributes { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_attributes_wrong_form)] -pub(crate) struct AttributesWrongForm { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_attribute_meta_item)] -pub(crate) struct AttributeMetaItem { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_attribute_single_word)] -pub(crate) struct AttributeSingleWord { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_helper_attribute_name_invalid)] -pub(crate) struct HelperAttributeNameInvalid { - #[primary_span] - pub span: Span, - pub name: Ident, -} - -#[derive(Diagnostic)] #[diag(expand_feature_removed, code = E0557)] #[note] pub(crate) struct FeatureRemoved<'a> { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 79ec79a2fdf..0517fd0419d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -693,7 +693,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { crate_name: self.cx.ecfg.crate_name, }); - self.cx.trace_macros_diag(); + self.cx.macro_error_and_trace_macros_diag(); guar } @@ -707,7 +707,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ) -> ErrorGuaranteed { let guar = self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path }); - self.cx.trace_macros_diag(); + self.cx.macro_error_and_trace_macros_diag(); guar } @@ -1048,7 +1048,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } annotate_err_with_kind(&mut err, kind, span); let guar = err.emit(); - self.cx.trace_macros_diag(); + self.cx.macro_error_and_trace_macros_diag(); kind.dummy(span, guar) } } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3f1fc841ea3..0324057e331 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -299,6 +299,7 @@ enum EofMatcherPositions { } /// Represents the possible results of an attempted parse. +#[derive(Debug)] pub(crate) enum ParseResult<T, F> { /// Parsed successfully. Success(T), diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 2f713a09b95..febe6f8b88c 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -280,7 +280,7 @@ fn expand_macro<'cx>( // Retry and emit a better error. let (span, guar) = diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules); - cx.trace_macros_diag(); + cx.macro_error_and_trace_macros_diag(); DummyResult::any(span, guar) } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e83f6a1df72..96501844264 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1363,6 +1363,17 @@ impl AttributeExt for Attribute { _ => None, } } + + fn is_proc_macro_attr(&self) -> bool { + matches!( + self, + Attribute::Parsed( + AttributeKind::ProcMacro(..) + | AttributeKind::ProcMacroAttribute(..) + | AttributeKind::ProcMacroDerive { .. } + ) + ) + } } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index bb1de5bcfc3..6e63ce31024 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -767,7 +767,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), DefKind::Static { .. } => { check_static_inhabited(tcx, def_id); check_static_linkage(tcx, def_id); - res = res.and(wfcheck::check_static_item(tcx, def_id)); + let ty = tcx.type_of(def_id).instantiate_identity(); + res = res.and(wfcheck::check_static_item( + tcx, def_id, ty, /* should_check_for_sync */ true, + )); } DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)), _ => unreachable!(), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 14ec82ede1c..a62efed13bc 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1180,12 +1180,13 @@ fn check_item_fn( } #[instrument(level = "debug", skip(tcx))] -pub(super) fn check_static_item( - tcx: TyCtxt<'_>, +pub(crate) fn check_static_item<'tcx>( + tcx: TyCtxt<'tcx>, item_id: LocalDefId, + ty: Ty<'tcx>, + should_check_for_sync: bool, ) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, item_id, |wfcx| { - let ty = tcx.type_of(item_id).instantiate_identity(); let span = tcx.ty_span(item_id); let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); @@ -1212,9 +1213,9 @@ pub(super) fn check_static_item( } // Ensure that the end result is `Sync` in a non-thread local `static`. - let should_check_for_sync = tcx.static_mutability(item_id.to_def_id()) - == Some(hir::Mutability::Not) + let should_check_for_sync = should_check_for_sync && !is_foreign_item + && tcx.static_mutability(item_id.to_def_id()) == Some(hir::Mutability::Not) && !tcx.is_thread_local_static(item_id.to_def_id()); if should_check_for_sync { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 902a2e15dff..22fb02714dd 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -14,6 +14,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span}; use super::{HirPlaceholderCollector, ItemCtxt, bad_placeholder}; +use crate::check::wfcheck::check_static_item; use crate::errors::TypeofReservedKeywordUsed; use crate::hir_ty_lowering::HirTyLowerer; @@ -217,7 +218,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ "static variable", ) } else { - icx.lower_ty(ty) + let ty = icx.lower_ty(ty); + // MIR relies on references to statics being scalars. + // Verify that here to avoid ill-formed MIR. + // We skip the `Sync` check to avoid cycles for type-alias-impl-trait, + // relying on the fact that non-Sync statics don't ICE the rest of the compiler. + match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) { + Ok(()) => ty, + Err(guar) => Ty::new_error(tcx, guar), + } } } ItemKind::Const(ident, _, ty, body_id) => { @@ -275,7 +284,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ForeignItemKind::Static(t, _, _) => icx.lower_ty(t), + ForeignItemKind::Static(ty, _, _) => { + let ty = icx.lower_ty(ty); + // MIR relies on references to statics being scalars. + // Verify that here to avoid ill-formed MIR. + // We skip the `Sync` check to avoid cycles for type-alias-impl-trait, + // relying on the fact that non-Sync statics don't ICE the rest of the compiler. + match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) { + Ok(()) => ty, + Err(guar) => Ty::new_error(tcx, guar), + } + } ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index dbfa7e6273c..e64af8fb7b3 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -264,6 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(within_macro_span, "due to this macro variable"); } self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true); + self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name); err.emit() } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fb6897c7d89..057fbe2fc4e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -208,6 +208,10 @@ fn configure_and_expand( // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); + if ecx.nb_macro_errors > 0 { + sess.dcx().abort_if_errors(); + } + // The rest is error reporting and stats sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index eb4c3703dbd..bf128b5914f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2870,7 +2870,7 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { if let hir::Expr { kind: hir::ExprKind::InlineAsm(hir::InlineAsm { - asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm, + asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm), template_strs, options, .. @@ -2878,6 +2878,15 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { .. } = expr { + // Non-generic naked functions are allowed to define arbitrary + // labels. + if *asm_macro == AsmMacro::NakedAsm { + let def_id = expr.hir_id.owner.def_id; + if !cx.tcx.generics_of(def_id).requires_monomorphization(cx.tcx) { + return; + } + } + // asm with `options(raw)` does not do replacement with `{` and `}`. let raw = options.contains(InlineAsmOptions::RAW); diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index c681deea779..ccfba715a1b 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -356,7 +356,16 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( let store = unerased_lint_store(tcx.sess); if store.late_module_passes.is_empty() { - late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); + // If all builtin lints can be skipped, there is no point in running `late_lint_mod_inner` + // at all. This happens often for dependencies built with `--cap-lints=allow`. + let dont_need_to_run = tcx.lints_that_dont_need_to_run(()); + let can_skip_lints = builtin_lints + .get_lints() + .iter() + .all(|lint| dont_need_to_run.contains(&LintId::of(lint))); + if !can_skip_lints { + late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); + } } else { let builtin_lints = Box::new(builtin_lints) as Box<dyn LateLintPass<'tcx>>; let mut binding = store diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 16eeb89207b..ac47897b568 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -933,6 +933,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool { let feature = if let Some(feature) = lint_id.lint.feature_gate && !self.features.enabled(feature) + && !span.allows_unstable(feature) { // Lint is behind a feature that is not enabled; eventually return false. feature diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index affea1b80ec..191eb721b34 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -92,7 +92,7 @@ macro_rules! expand_combined_late_lint_pass_methods { /// Combines multiple lints passes into a single lint pass, at compile time, /// for maximum speed. Each `check_foo` method in `$methods` within this pass /// simply calls `check_foo` once per `$pass`. Compare with -/// `LateLintPassObjects`, which is similar, but combines lint passes at +/// `RuntimeCombinedLateLintPass`, which is similar, but combines lint passes at /// runtime. #[macro_export] macro_rules! declare_combined_late_lint_pass { @@ -123,10 +123,10 @@ macro_rules! declare_combined_late_lint_pass { #[allow(rustc::lint_pass_impl_without_macro)] impl $crate::LintPass for $name { fn name(&self) -> &'static str { - panic!() + stringify!($name) } fn get_lints(&self) -> LintVec { - panic!() + $name::get_lints() } } ) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a9eb1739f7f..df9f3a500d9 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1340,7 +1340,15 @@ impl EarlyLintPass for UnusedParens { self.with_self_ty_parens = false; } ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => { - self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound); + // If this type itself appears in no-bounds position, we propagate its + // potentially tighter constraint or risk a false posive (issue 143653). + let own_constraint = self.in_no_bounds_pos.get(&ty.id); + let constraint = match own_constraint { + Some(NoBoundsException::None) => NoBoundsException::None, + Some(NoBoundsException::OneBound) => NoBoundsException::OneBound, + None => NoBoundsException::OneBound, + }; + self.in_no_bounds_pos.insert(mut_ty.ty.id, constraint); } ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => { for i in 0..bounds.len() { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 82568ed4ae1..c9814beedd6 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1610,7 +1610,7 @@ extern "C" void LLVMRustPositionBefore(LLVMBuilderRef B, LLVMValueRef Instr) { extern "C" void LLVMRustPositionAfter(LLVMBuilderRef B, LLVMValueRef Instr) { if (auto I = dyn_cast<Instruction>(unwrap<Value>(Instr))) { - auto J = I->getNextNonDebugInstruction(); + auto J = I->getNextNode(); unwrap(B)->SetInsertPoint(J); } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5cd98038fc6..ffb33c67f8a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -5,7 +5,7 @@ use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use rustc_attr_data_structures::EncodeCrossCrate; +use rustc_attr_data_structures::{AttributeKind, EncodeCrossCrate, find_attr}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{join, par_for_each_in}; @@ -1965,18 +1965,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Proc-macros may have attributes like `#[allow_internal_unstable]`, // so downstream crates need access to them. let attrs = tcx.hir_attrs(proc_macro); - let macro_kind = if ast::attr::contains_name(attrs, sym::proc_macro) { + let macro_kind = if find_attr!(attrs, AttributeKind::ProcMacro(..)) { MacroKind::Bang - } else if ast::attr::contains_name(attrs, sym::proc_macro_attribute) { + } else if find_attr!(attrs, AttributeKind::ProcMacroAttribute(..)) { MacroKind::Attr - } else if let Some(attr) = ast::attr::find_by_name(attrs, sym::proc_macro_derive) { - // This unwrap chain should have been checked by the proc-macro harness. - name = attr.meta_item_list().unwrap()[0] - .meta_item() - .unwrap() - .ident() - .unwrap() - .name; + } else if let Some(trait_name) = find_attr!(attrs, AttributeKind::ProcMacroDerive { trait_name, ..} => trait_name) + { + name = *trait_name; MacroKind::Derive } else { bug!("Unknown proc-macro type for item {:?}", id); @@ -2124,11 +2119,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; let def_id = id.owner_id.to_def_id(); - self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); - if of_trait && let Some(header) = tcx.impl_trait_header(def_id) { record!(self.tables.impl_trait_header[def_id] <- header); + self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); + let trait_ref = header.trait_ref.instantiate_identity(); let simplified_self_ty = fast_reject::simplify_type( self.tcx, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 2b0cfb86564..3e895c6b280 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -426,7 +426,12 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Trying to set discriminant to the niched variant, but the value does not match. InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> }, /// ABI-incompatible argument types. - AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> }, + AbiMismatchArgument { + /// The index of the argument whose type is wrong. + arg_idx: usize, + caller_ty: Ty<'tcx>, + callee_ty: Ty<'tcx>, + }, /// ABI-incompatible return types. AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> }, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 66d1335e763..6f21160d1f6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1041,11 +1041,13 @@ const NUM_PREINTERNED_TY_VARS: u32 = 100; const NUM_PREINTERNED_FRESH_TYS: u32 = 20; const NUM_PREINTERNED_FRESH_INT_TYS: u32 = 3; const NUM_PREINTERNED_FRESH_FLOAT_TYS: u32 = 3; +const NUM_PREINTERNED_ANON_BOUND_TYS_I: u32 = 3; +const NUM_PREINTERNED_ANON_BOUND_TYS_V: u32 = 20; // This number may seem high, but it is reached in all but the smallest crates. const NUM_PREINTERNED_RE_VARS: u32 = 500; -const NUM_PREINTERNED_RE_LATE_BOUNDS_I: u32 = 2; -const NUM_PREINTERNED_RE_LATE_BOUNDS_V: u32 = 20; +const NUM_PREINTERNED_ANON_RE_BOUNDS_I: u32 = 3; +const NUM_PREINTERNED_ANON_RE_BOUNDS_V: u32 = 20; pub struct CommonTypes<'tcx> { pub unit: Ty<'tcx>, @@ -1088,6 +1090,11 @@ pub struct CommonTypes<'tcx> { /// Pre-interned `Infer(ty::FreshFloatTy(n))` for small values of `n`. pub fresh_float_tys: Vec<Ty<'tcx>>, + + /// Pre-interned values of the form: + /// `Bound(DebruijnIndex(i), BoundTy { var: v, kind: BoundTyKind::Anon})` + /// for small values of `i` and `v`. + pub anon_bound_tys: Vec<Vec<Ty<'tcx>>>, } pub struct CommonLifetimes<'tcx> { @@ -1101,9 +1108,9 @@ pub struct CommonLifetimes<'tcx> { pub re_vars: Vec<Region<'tcx>>, /// Pre-interned values of the form: - /// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon })` + /// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BoundRegionKind::Anon })` /// for small values of `i` and `v`. - pub re_late_bounds: Vec<Vec<Region<'tcx>>>, + pub anon_re_bounds: Vec<Vec<Region<'tcx>>>, } pub struct CommonConsts<'tcx> { @@ -1131,6 +1138,19 @@ impl<'tcx> CommonTypes<'tcx> { let fresh_float_tys: Vec<_> = (0..NUM_PREINTERNED_FRESH_FLOAT_TYS).map(|n| mk(Infer(ty::FreshFloatTy(n)))).collect(); + let anon_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_I) + .map(|i| { + (0..NUM_PREINTERNED_ANON_BOUND_TYS_V) + .map(|v| { + mk(ty::Bound( + ty::DebruijnIndex::from(i), + ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon }, + )) + }) + .collect() + }) + .collect(); + CommonTypes { unit: mk(Tuple(List::empty())), bool: mk(Bool), @@ -1161,6 +1181,7 @@ impl<'tcx> CommonTypes<'tcx> { fresh_tys, fresh_int_tys, fresh_float_tys, + anon_bound_tys, } } } @@ -1176,9 +1197,9 @@ impl<'tcx> CommonLifetimes<'tcx> { let re_vars = (0..NUM_PREINTERNED_RE_VARS).map(|n| mk(ty::ReVar(ty::RegionVid::from(n)))).collect(); - let re_late_bounds = (0..NUM_PREINTERNED_RE_LATE_BOUNDS_I) + let anon_re_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_I) .map(|i| { - (0..NUM_PREINTERNED_RE_LATE_BOUNDS_V) + (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V) .map(|v| { mk(ty::ReBound( ty::DebruijnIndex::from(i), @@ -1196,7 +1217,7 @@ impl<'tcx> CommonLifetimes<'tcx> { re_static: mk(ty::ReStatic), re_erased: mk(ty::ReErased), re_vars, - re_late_bounds, + anon_re_bounds, } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a7cde2ad485..4c95f0748d3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2024,7 +2024,10 @@ impl<'tcx> TyCtxt<'tcx> { && let Some(def_id) = def_id.as_local() && let outer = self.def_span(def_id).ctxt().outer_expn_data() && matches!(outer.kind, ExpnKind::Macro(MacroKind::Derive, _)) - && self.has_attr(outer.macro_def_id.unwrap(), sym::rustc_builtin_macro) + && find_attr!( + self.get_all_attrs(outer.macro_def_id.unwrap()), + AttributeKind::RustcBuiltinMacro { .. } + ) { true } else { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9ee64df0ad0..fd4472e1f96 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -86,7 +86,7 @@ macro_rules! define_helper { impl $helper { pub fn new() -> $helper { - $helper($tl.with(|c| c.replace(true))) + $helper($tl.replace(true)) } } @@ -100,12 +100,12 @@ macro_rules! define_helper { impl Drop for $helper { fn drop(&mut self) { - $tl.with(|c| c.set(self.0)) + $tl.set(self.0) } } pub fn $name() -> bool { - $tl.with(|c| c.get()) + $tl.get() } )+ } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 51be93d9a72..5cf96072177 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -54,7 +54,7 @@ impl<'tcx> Region<'tcx> { ) -> Region<'tcx> { // Use a pre-interned one when possible. if let ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon } = bound_region - && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize()) + && let Some(inner) = tcx.lifetimes.anon_re_bounds.get(debruijn.as_usize()) && let Some(re) = inner.get(var.as_usize()).copied() { re diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8bb3b3f1263..4569596cfbe 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -485,7 +485,15 @@ impl<'tcx> Ty<'tcx> { index: ty::DebruijnIndex, bound_ty: ty::BoundTy, ) -> Ty<'tcx> { - Ty::new(tcx, Bound(index, bound_ty)) + // Use a pre-interned one when possible. + if let ty::BoundTy { var, kind: ty::BoundTyKind::Anon } = bound_ty + && let Some(inner) = tcx.types.anon_bound_tys.get(index.as_usize()) + && let Some(ty) = inner.get(var.as_usize()).copied() + { + ty + } else { + Ty::new(tcx, Bound(index, bound_ty)) + } } #[inline] diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index e339520cd86..abfe8eb66dd 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -86,10 +86,16 @@ mir_build_confused = missing patterns are not covered because `{$variable}` is i mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]` .label = this value is too generic - .note = the value must be a literal or a monomorphic const mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value +mir_build_const_continue_not_const = could not determine the target branch for this `#[const_continue]` + .help = try extracting the expression into a `const` item + +mir_build_const_continue_not_const_const_block = `const` blocks may use generics, and are not evaluated early enough +mir_build_const_continue_not_const_const_other = this value must be a literal or a monomorphic const +mir_build_const_continue_not_const_constant_parameter = constant parameters may use generics, and are not evaluated early enough + mir_build_const_continue_unknown_jump_target = the target of this `#[const_continue]` is not statically known .label = this value must be a literal or a monomorphic const diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 12a56d7c5ea..1240b34cf9d 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -100,7 +100,9 @@ use tracing::{debug, instrument}; use super::matches::BuiltMatchTree; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; -use crate::errors::{ConstContinueBadConst, ConstContinueUnknownJumpTarget}; +use crate::errors::{ + ConstContinueBadConst, ConstContinueNotMonomorphicConst, ConstContinueUnknownJumpTarget, +}; #[derive(Debug)] pub(crate) struct Scopes<'tcx> { @@ -867,7 +869,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "break value must be a scope") }; - let constant = match &self.thir[value].kind { + let expr = &self.thir[value]; + let constant = match &expr.kind { ExprKind::Adt(box AdtExpr { variant_index, fields, base, .. }) => { assert!(matches!(base, AdtExprBase::None)); assert!(fields.is_empty()); @@ -887,7 +890,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ), } } - _ => self.as_constant(&self.thir[value]), + + ExprKind::Literal { .. } + | ExprKind::NonHirLiteral { .. } + | ExprKind::ZstLiteral { .. } + | ExprKind::NamedConst { .. } => self.as_constant(&self.thir[value]), + + other => { + use crate::errors::ConstContinueNotMonomorphicConstReason as Reason; + + let span = expr.span; + let reason = match other { + ExprKind::ConstParam { .. } => Reason::ConstantParameter { span }, + ExprKind::ConstBlock { .. } => Reason::ConstBlock { span }, + _ => Reason::Other { span }, + }; + + self.tcx + .dcx() + .emit_err(ConstContinueNotMonomorphicConst { span: expr.span, reason }); + return block.unit(); + } }; let break_index = self diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 16b49bf384c..f1fbd5c4a49 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1214,6 +1214,38 @@ pub(crate) struct LoopMatchArmWithGuard { } #[derive(Diagnostic)] +#[diag(mir_build_const_continue_not_const)] +#[help] +pub(crate) struct ConstContinueNotMonomorphicConst { + #[primary_span] + pub span: Span, + + #[subdiagnostic] + pub reason: ConstContinueNotMonomorphicConstReason, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ConstContinueNotMonomorphicConstReason { + #[label(mir_build_const_continue_not_const_constant_parameter)] + ConstantParameter { + #[primary_span] + span: Span, + }, + + #[label(mir_build_const_continue_not_const_const_block)] + ConstBlock { + #[primary_span] + span: Span, + }, + + #[label(mir_build_const_continue_not_const_const_other)] + Other { + #[primary_span] + span: Span, + }, +} + +#[derive(Diagnostic)] #[diag(mir_build_const_continue_bad_const)] pub(crate) struct ConstContinueBadConst { #[primary_span] diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ddeae093df5..ec76076020e 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,8 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_middle::ty::TyCtxt; -use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span}; +use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::instrument; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; @@ -84,18 +83,8 @@ pub(super) fn extract_refined_covspans<'tcx>( // Discard any span that overlaps with a hole. discard_spans_overlapping_holes(&mut covspans, &holes); - // Discard spans that overlap in unwanted ways. + // Perform more refinement steps after holes have been dealt with. let mut covspans = remove_unwanted_overlapping_spans(covspans); - - // For all empty spans, either enlarge them to be non-empty, or discard them. - let source_map = tcx.sess.source_map(); - covspans.retain_mut(|covspan| { - let Some(span) = ensure_non_empty_span(source_map, covspan.span) else { return false }; - covspan.span = span; - true - }); - - // Merge covspans that can be merged. covspans.dedup_by(|b, a| a.merge_if_eligible(b)); code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { @@ -241,26 +230,3 @@ fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { // - Both have the same start and span A extends further right .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) } - -fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> { - if !span.is_empty() { - return Some(span); - } - - // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'. - source_map - .span_to_source(span, |src, start, end| try { - // Adjusting span endpoints by `BytePos(1)` is normally a bug, - // but in this case we have specifically checked that the character - // we're skipping over is one of two specific ASCII characters, so - // adjusting by exactly 1 byte is correct. - if src.as_bytes().get(end).copied() == Some(b'{') { - Some(span.with_hi(span.hi() + BytePos(1))) - } else if start > 0 && src.as_bytes()[start - 1] == b'}' { - Some(span.with_lo(span.lo() - BytePos(1))) - } else { - None - } - }) - .ok()? -} diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index c281ef216c7..b2d40146348 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -10,8 +10,8 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ - self as ty, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, - TypeVisitor, TypingMode, Upcast as _, elaborate, + self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate, }; use tracing::{debug, instrument}; @@ -132,6 +132,7 @@ where }) .enter(|ecx| { Self::match_assumption(ecx, goal, assumption, |ecx| { + ecx.try_evaluate_added_goals()?; source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -1069,8 +1070,10 @@ where } else { ControlFlow::Continue(()) } - } else { + } else if ty.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) { ty.super_visit_with(self) + } else { + ControlFlow::Continue(()) } } @@ -1086,8 +1089,10 @@ where } else { ControlFlow::Continue(()) } - } else { + } else if ct.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) { ct.super_visit_with(self) + } else { + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index a92012f8329..88f93782de1 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -9,6 +9,7 @@ bitflags = "2.4.1" rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 73a341c3a3d..bc4c605afad 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -1,11 +1,14 @@ //! Meta-syntax validation logic of attributes for post-expansion. +use std::slice; + use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Safety, }; +use rustc_attr_parsing::{AttributeParser, Late}; use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_session::errors::report_lit_error; @@ -266,67 +269,7 @@ pub fn check_builtin_meta_item( ) { if !is_attr_template_compatible(&template, &meta.kind) { // attrs with new parsers are locally validated so excluded here - if matches!( - name, - sym::inline - | sym::export_stable - | sym::ffi_const - | sym::ffi_pure - | sym::rustc_std_internal_symbol - | sym::may_dangle - | sym::rustc_as_ptr - | sym::rustc_pub_transparent - | sym::rustc_const_stable_indirect - | sym::rustc_force_inline - | sym::rustc_confusables - | sym::rustc_skip_during_method_dispatch - | sym::rustc_pass_by_value - | sym::rustc_deny_explicit_impl - | sym::rustc_do_not_implement_via_object - | sym::rustc_coinductive - | sym::const_trait - | sym::stable - | sym::unstable - | sym::rustc_allowed_through_unstable_modules - | sym::rustc_specialization_trait - | sym::rustc_unsafe_specialization_marker - | sym::rustc_allow_incoherent_impl - | sym::rustc_coherence_is_core - | sym::marker - | sym::fundamental - | sym::rustc_paren_sugar - | sym::type_const - | sym::repr - // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres - // ambiguity - | sym::rustc_align - | sym::deprecated - | sym::optimize - | sym::pointee - | sym::cold - | sym::target_feature - | sym::rustc_allow_const_fn_unstable - | sym::macro_use - | sym::macro_escape - | sym::naked - | sym::no_mangle - | sym::non_exhaustive - | sym::omit_gdb_pretty_printer_section - | sym::path - | sym::ignore - | sym::must_use - | sym::track_caller - | sym::link_name - | sym::link_ordinal - | sym::export_name - | sym::rustc_macro_transparency - | sym::link_section - | sym::rustc_layout_scalar_valid_range_start - | sym::rustc_layout_scalar_valid_range_end - | sym::no_implicit_prelude - | sym::automatically_derived - | sym::coverage - ) { + if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) { return; } emit_malformed_attribute(psess, style, meta.span, name, template); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4b524bb2bd2..0b329cc38b0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -130,6 +130,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs { let mut style = None; match attr { + Attribute::Parsed(AttributeKind::ProcMacro(_)) => { + self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) + } + Attribute::Parsed(AttributeKind::ProcMacroAttribute(_)) => { + self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); + } + Attribute::Parsed(AttributeKind::ProcMacroDerive { span: attr_span, .. }) => { + self.check_generic_attr( + hir_id, + sym::proc_macro_derive, + *attr_span, + target, + Target::Fn, + ); + self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) + } Attribute::Parsed( AttributeKind::SkipDuringMethodDispatch { span: attr_span, .. } | AttributeKind::Coinductive(attr_span) @@ -275,6 +291,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroTransparency(_) | AttributeKind::Pointee(..) | AttributeKind::Dummy + | AttributeKind::RustcBuiltinMacro { .. } | AttributeKind::OmitGdbPrettyPrinterSection, ) => { /* do nothing */ } Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { @@ -373,16 +390,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::should_panic, ..] => { self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn) } - [sym::proc_macro, ..] => { - self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) - } - [sym::proc_macro_attribute, ..] => { - self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); - } - [sym::proc_macro_derive, ..] => { - self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn); - self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) - } [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 09685640e50..9a9e0db964c 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -950,9 +950,7 @@ impl<Cx: PatCx> Constructor<Cx> { } } Never => write!(f, "!")?, - Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => { - write!(f, "_ : {:?}", ty)? - } + Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => write!(f, "_")?, } Ok(()) } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 66df35f9ee4..d9bb93a829b 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -57,6 +57,13 @@ pub trait PatCx: Sized + fmt::Debug { fn is_exhaustive_patterns_feature_on(&self) -> bool; + /// Whether to ensure the non-exhaustiveness witnesses we report for a complete set. This is + /// `false` by default to avoid some exponential blowup cases such as + /// <https://github.com/rust-lang/rust/issues/118437>. + fn exhaustive_witnesses(&self) -> bool { + false + } + /// The number of fields for this constructor. fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize; diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index b1c646e9884..19446a1efe9 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -994,7 +994,8 @@ impl<Cx: PatCx> PlaceInfo<Cx> { if !missing_ctors.is_empty() && !report_individual_missing_ctors { // Report `_` as missing. missing_ctors = vec![Constructor::Wildcard]; - } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { + } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) && !cx.exhaustive_witnesses() + { // We need to report a `_` anyway, so listing other constructors would be redundant. // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked // up by diagnostics to add a note about why `_` is required here. @@ -1747,7 +1748,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( // `ctor` is *irrelevant* if there's another constructor in `split_ctors` that matches // strictly fewer rows. In that case we can sometimes skip it. See the top of the file for // details. - let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty(); + let ctor_is_relevant = matches!(ctor, Constructor::Missing) + || missing_ctors.is_empty() + || mcx.tycx.exhaustive_witnesses(); let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?; let mut witnesses = ensure_sufficient_stack(|| { compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix) diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs index 0b939ef7816..94f2a127b9b 100644 --- a/compiler/rustc_pattern_analysis/tests/common/mod.rs +++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs @@ -1,3 +1,4 @@ +#![allow(dead_code, unreachable_pub)] use rustc_pattern_analysis::constructor::{ Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility, }; @@ -22,8 +23,10 @@ fn init_tracing() { .try_init(); } +pub(super) const UNIT: Ty = Ty::Tuple(&[]); +pub(super) const NEVER: Ty = Ty::Enum(&[]); + /// A simple set of types. -#[allow(dead_code)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(super) enum Ty { /// Booleans @@ -38,6 +41,8 @@ pub(super) enum Ty { BigStruct { arity: usize, ty: &'static Ty }, /// A enum with `arity` variants of type `ty`. BigEnum { arity: usize, ty: &'static Ty }, + /// Like `Enum` but non-exhaustive. + NonExhaustiveEnum(&'static [Ty]), } /// The important logic. @@ -47,7 +52,7 @@ impl Ty { match (ctor, *self) { (Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(), (Struct, Ty::BigStruct { arity, ty }) => (0..arity).map(|_| *ty).collect(), - (Variant(i), Ty::Enum(tys)) => vec![tys[*i]], + (Variant(i), Ty::Enum(tys) | Ty::NonExhaustiveEnum(tys)) => vec![tys[*i]], (Variant(_), Ty::BigEnum { ty, .. }) => vec![*ty], (Bool(..) | IntRange(..) | NonExhaustive | Missing | Wildcard, _) => vec![], _ => panic!("Unexpected ctor {ctor:?} for type {self:?}"), @@ -61,6 +66,7 @@ impl Ty { Ty::Enum(tys) => tys.iter().all(|ty| ty.is_empty()), Ty::BigStruct { arity, ty } => arity != 0 && ty.is_empty(), Ty::BigEnum { arity, ty } => arity == 0 || ty.is_empty(), + Ty::NonExhaustiveEnum(..) => false, } } @@ -90,6 +96,19 @@ impl Ty { .collect(), non_exhaustive: false, }, + Ty::NonExhaustiveEnum(tys) => ConstructorSet::Variants { + variants: tys + .iter() + .map(|ty| { + if ty.is_empty() { + VariantVisibility::Empty + } else { + VariantVisibility::Visible + } + }) + .collect(), + non_exhaustive: true, + }, Ty::BigEnum { arity: 0, .. } => ConstructorSet::NoConstructors, Ty::BigEnum { arity, ty } => { let vis = if ty.is_empty() { @@ -113,7 +132,9 @@ impl Ty { match (*self, ctor) { (Ty::Tuple(..), _) => Ok(()), (Ty::BigStruct { .. }, _) => write!(f, "BigStruct"), - (Ty::Enum(..), Constructor::Variant(i)) => write!(f, "Enum::Variant{i}"), + (Ty::Enum(..) | Ty::NonExhaustiveEnum(..), Constructor::Variant(i)) => { + write!(f, "Enum::Variant{i}") + } (Ty::BigEnum { .. }, Constructor::Variant(i)) => write!(f, "BigEnum::Variant{i}"), _ => write!(f, "{:?}::{:?}", self, ctor), } @@ -126,10 +147,11 @@ pub(super) fn compute_match_usefulness<'p>( ty: Ty, scrut_validity: PlaceValidity, complexity_limit: usize, + exhaustive_witnesses: bool, ) -> Result<UsefulnessReport<'p, Cx>, ()> { init_tracing(); rustc_pattern_analysis::usefulness::compute_match_usefulness( - &Cx, + &Cx { exhaustive_witnesses }, arms, ty, scrut_validity, @@ -138,7 +160,9 @@ pub(super) fn compute_match_usefulness<'p>( } #[derive(Debug)] -pub(super) struct Cx; +pub(super) struct Cx { + exhaustive_witnesses: bool, +} /// The context for pattern analysis. Forwards anything interesting to `Ty` methods. impl PatCx for Cx { @@ -153,6 +177,10 @@ impl PatCx for Cx { false } + fn exhaustive_witnesses(&self) -> bool { + self.exhaustive_witnesses + } + fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize { ty.sub_tys(ctor).len() } @@ -219,16 +247,18 @@ macro_rules! pats { // Entrypoint // Parse `type; ..` ($ty:expr; $($rest:tt)*) => {{ - #[allow(unused_imports)] + #[allow(unused)] use rustc_pattern_analysis::{ constructor::{Constructor, IntRange, MaybeInfiniteInt, RangeEnd}, - pat::DeconstructedPat, + pat::{DeconstructedPat, IndexedPat}, }; let ty = $ty; // The heart of the macro is designed to push `IndexedPat`s into a `Vec`, so we work around // that. + #[allow(unused)] let sub_tys = ::std::iter::repeat(&ty); - let mut vec = Vec::new(); + #[allow(unused)] + let mut vec: Vec<IndexedPat<_>> = Vec::new(); pats!(@ctor(vec:vec, sub_tys:sub_tys, idx:0) $($rest)*); vec.into_iter().map(|ipat| ipat.pat).collect::<Vec<_>>() }}; @@ -263,6 +293,8 @@ macro_rules! pats { let ctor = Constructor::Wildcard; pats!(@pat($($args)*, ctor:ctor) $($rest)*) }}; + // Nothing + (@ctor($($args:tt)*)) => {}; // Integers and int ranges (@ctor($($args:tt)*) $($start:literal)?..$end:literal $($rest:tt)*) => {{ diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs index 93aecafe48d..4754476f383 100644 --- a/compiler/rustc_pattern_analysis/tests/complexity.rs +++ b/compiler/rustc_pattern_analysis/tests/complexity.rs @@ -16,7 +16,7 @@ fn check(patterns: &[DeconstructedPat<Cx>], complexity_limit: usize) -> Result<( let ty = *patterns[0].ty(); let arms: Vec<_> = patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect(); - compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, complexity_limit) + compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, complexity_limit, false) .map(|_report| ()) } diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs index 3b8f346ef19..14ca0d057f0 100644 --- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs +++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs @@ -11,16 +11,30 @@ use rustc_pattern_analysis::usefulness::PlaceValidity; mod common; /// Analyze a match made of these patterns. -fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> { - let ty = *patterns[0].ty(); +fn run( + ty: Ty, + patterns: Vec<DeconstructedPat<Cx>>, + exhaustive_witnesses: bool, +) -> Vec<WitnessPat<Cx>> { let arms: Vec<_> = patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect(); - let report = - compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX) - .unwrap(); + let report = compute_match_usefulness( + arms.as_slice(), + ty, + PlaceValidity::ValidOnly, + usize::MAX, + exhaustive_witnesses, + ) + .unwrap(); report.non_exhaustiveness_witnesses } +/// Analyze a match made of these patterns. Panics if there are no patterns +fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> { + let ty = *patterns[0].ty(); + run(ty, patterns, true) +} + #[track_caller] fn assert_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) { let witnesses = check(patterns); @@ -35,6 +49,26 @@ fn assert_non_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) { assert!(!witnesses.is_empty()) } +use WhichWitnesses::*; +enum WhichWitnesses { + AllOfThem, + OnlySome, +} + +#[track_caller] +/// We take the type as input to support empty matches. +fn assert_witnesses( + which: WhichWitnesses, + ty: Ty, + patterns: Vec<DeconstructedPat<Cx>>, + expected: Vec<&str>, +) { + let exhaustive_wit = matches!(which, AllOfThem); + let witnesses = run(ty, patterns, exhaustive_wit); + let witnesses: Vec<_> = witnesses.iter().map(|w| format!("{w:?}")).collect(); + assert_eq!(witnesses, expected) +} + #[test] fn test_int_ranges() { let ty = Ty::U8; @@ -59,6 +93,8 @@ fn test_int_ranges() { #[test] fn test_nested() { + // enum E { A(bool), B(bool) } + // ty = (E, E) let ty = Ty::BigStruct { arity: 2, ty: &Ty::BigEnum { arity: 2, ty: &Ty::Bool } }; assert_non_exhaustive(pats!(ty; Struct(Variant.0, _), @@ -79,9 +115,73 @@ fn test_nested() { } #[test] +fn test_witnesses() { + // TY = Option<bool> + const TY: Ty = Ty::Enum(&[Ty::Bool, UNIT]); + // ty = (Option<bool>, Option<bool>) + let ty = Ty::Tuple(&[TY, TY]); + assert_witnesses(AllOfThem, ty, vec![], vec!["(_, _)"]); + assert_witnesses( + OnlySome, + ty, + pats!(ty; + (Variant.0(false), Variant.0(false)), + ), + vec!["(Enum::Variant1(_), _)"], + ); + assert_witnesses( + AllOfThem, + ty, + pats!(ty; + (Variant.0(false), Variant.0(false)), + ), + vec![ + "(Enum::Variant0(false), Enum::Variant0(true))", + "(Enum::Variant0(false), Enum::Variant1(_))", + "(Enum::Variant0(true), _)", + "(Enum::Variant1(_), _)", + ], + ); + assert_witnesses( + OnlySome, + ty, + pats!(ty; + (_, Variant.0(false)), + ), + vec!["(_, Enum::Variant1(_))"], + ); + assert_witnesses( + AllOfThem, + ty, + pats!(ty; + (_, Variant.0(false)), + ), + vec!["(_, Enum::Variant0(true))", "(_, Enum::Variant1(_))"], + ); + + let ty = Ty::NonExhaustiveEnum(&[UNIT, UNIT, UNIT]); + assert_witnesses( + OnlySome, + ty, + pats!(ty; + Variant.0, + ), + vec!["_"], + ); + assert_witnesses( + AllOfThem, + ty, + pats!(ty; + Variant.0, + ), + vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"], + ); +} + +#[test] fn test_empty() { // `TY = Result<bool, !>` - const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Enum(&[])]); + const TY: Ty = Ty::Enum(&[Ty::Bool, NEVER]); assert_exhaustive(pats!(TY; Variant.0, )); diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs index 8e6f84dcbc8..d4d390517e2 100644 --- a/compiler/rustc_pattern_analysis/tests/intersection.rs +++ b/compiler/rustc_pattern_analysis/tests/intersection.rs @@ -16,7 +16,7 @@ fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<Vec<usize>> { let arms: Vec<_> = patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect(); let report = - compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX) + compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX, false) .unwrap(); report.arm_intersections.into_iter().map(|bitset| bitset.iter().collect()).collect() } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 06e59eb4ccc..e74de5edc42 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -720,7 +720,7 @@ fn incremental_verify_ich_failed<Tcx>( static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) }; }; - let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true)); + let old_in_panic = INSIDE_VERIFY_PANIC.replace(true); if old_in_panic { tcx.sess().dcx().emit_err(crate::error::Reentrant); @@ -739,7 +739,7 @@ fn incremental_verify_ich_failed<Tcx>( panic!("Found unstable fingerprints for {dep_node:?}: {}", result()); } - INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic)); + INSIDE_VERIFY_PANIC.set(old_in_panic); } /// Ensure that either this query has all green inputs or been executed. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 83ec037a975..b15b478a6be 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -23,9 +23,9 @@ use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; -use rustc_middle::bug; use rustc_middle::metadata::ModChild; use rustc_middle::ty::{Feed, Visibility}; +use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use thin_vec::ThinVec; @@ -46,30 +46,59 @@ type Res = def::Res<NodeId>; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. - pub(crate) fn define_binding( + pub(crate) fn define_binding_local( &mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, binding: NameBinding<'ra>, ) { - if let Err(old_binding) = self.try_define(parent, ident, ns, binding, false) { + if let Err(old_binding) = self.try_define_local(parent, ident, ns, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } - fn define( + fn define_local( &mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, res: Res, - vis: Visibility<impl Into<DefId>>, + vis: Visibility, span: Span, expn_id: LocalExpnId, ) { let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id); - self.define_binding(parent, ident, ns, binding) + self.define_binding_local(parent, ident, ns, binding); + } + + fn define_extern( + &self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + res: Res, + vis: Visibility<DefId>, + span: Span, + expn_id: LocalExpnId, + ) { + let binding = self.arenas.new_res_binding(res, vis, span, expn_id); + // Even if underscore names cannot be looked up, we still need to add them to modules, + // because they can be fetched by glob imports from those modules, and bring traits + // into scope both directly and through glob imports. + let key = BindingKey::new_disambiguated(ident, ns, || { + parent.underscore_disambiguator.update(|d| d + 1); + parent.underscore_disambiguator.get() + }); + if self + .resolution_or_default(parent, key) + .borrow_mut() + .non_glob_binding + .replace(binding) + .is_some() + { + span_bug!(span, "an external binding was already defined"); + } } /// Walks up the tree of definitions starting at `def_id`, @@ -192,7 +221,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { visitor.parent_scope.macro_rules } - pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'ra>) { + pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) { for child in self.tcx.module_children(module.def_id()) { let parent_scope = ParentScope::module(module, self); self.build_reduced_graph_for_external_crate_res(child, parent_scope) @@ -201,7 +230,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_res( - &mut self, + &self, child: &ModChild, parent_scope: ParentScope<'ra>, ) { @@ -232,7 +261,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _, ) | Res::PrimTy(..) - | Res::ToolMod => self.define(parent, ident, TypeNS, res, vis, span, expansion), + | Res::ToolMod => self.define_extern(parent, ident, TypeNS, res, vis, span, expansion), Res::Def( DefKind::Fn | DefKind::AssocFn @@ -241,9 +270,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | DefKind::AssocConst | DefKind::Ctor(..), _, - ) => self.define(parent, ident, ValueNS, res, vis, span, expansion), + ) => self.define_extern(parent, ident, ValueNS, res, vis, span, expansion), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define(parent, ident, MacroNS, res, vis, span, expansion) + self.define_extern(parent, ident, MacroNS, res, vis, span, expansion) } Res::Def( DefKind::TyParam @@ -452,8 +481,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { let key = BindingKey::new(target, ns); - let mut resolution = this.resolution(current_module, key).borrow_mut(); - resolution.single_imports.insert(import); + this.resolution_or_default(current_module, key) + .borrow_mut() + .single_imports + .insert(import); } }); } @@ -709,7 +740,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let expansion = parent_scope.expansion; // Define a name in the type namespace if it is not anonymous. - self.r.define(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion); + self.r.define_local(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion); self.r.feed_visibility(feed, adt_vis); let def_id = feed.key(); @@ -761,7 +792,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); + self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion); if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { self.r.mods_with_parse_errors.insert(def_id); @@ -780,10 +811,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Const(box ConstItem { ident, .. }) | ItemKind::Delegation(box Delegation { ident, .. }) | ItemKind::Static(box StaticItem { ident, .. }) => { - self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); + self.r.define_local(parent, ident, ValueNS, res, vis, sp, expansion); } ItemKind::Fn(box Fn { ident, .. }) => { - self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); + self.r.define_local(parent, ident, ValueNS, res, vis, sp, expansion); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). @@ -792,11 +823,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // These items live in the type namespace. ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { - self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); + self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion); } ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { - self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); + self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion); self.parent_scope.module = self.r.new_local_module( Some(parent), @@ -848,7 +879,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion); + self.r.define_local(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion); self.r.feed_visibility(feed, ctor_vis); // We need the field visibility spans also for the constructor for E0603. self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields()); @@ -972,7 +1003,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } } - self.r.define_binding(parent, ident, TypeNS, imported_binding); + self.r.define_binding_local(parent, ident, TypeNS, imported_binding); } /// Constructs the reduced graph for one foreign item. @@ -989,7 +1020,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); - self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); + self.r.define_local(parent, ident, ns, self.res(def_id), vis, item.span, expansion); self.r.feed_visibility(feed, vis); } @@ -1072,7 +1103,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if let Some(span) = import_all { let import = macro_use_import(self, span, false); self.r.potentially_unused_imports.push(import); - module.for_each_child(self, |this, ident, ns, binding| { + module.for_each_child_mut(self, |this, ident, ns, binding| { if ns == MacroNS { let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module) { @@ -1237,7 +1268,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); - self.r.define_binding(self.r.graph_root, ident, MacroNS, import_binding); + self.r.define_binding_local(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id); @@ -1265,7 +1296,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if !vis.is_public() { self.insert_unused_macro(ident, def_id, item.id); } - self.r.define(module, ident, MacroNS, res, vis, span, expansion); + self.r.define_local(module, ident, MacroNS, res, vis, span, expansion); self.r.feed_visibility(feed, vis); self.parent_scope.macro_rules } @@ -1401,7 +1432,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if ctxt == AssocCtxt::Trait { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; - self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); + self.r.define_local(parent, ident, ns, self.res(def_id), vis, item.span, expansion); } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) && ident.name != kw::Underscore { @@ -1489,7 +1520,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(variant.id); let def_id = feed.key(); let vis = self.resolve_visibility(&variant.vis); - self.r.define(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id); + self.r.define_local(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id); self.r.feed_visibility(feed, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. @@ -1505,7 +1536,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id); + self.r.define_local(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id); self.r.feed_visibility(feed, ctor_vis); } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 81ee02ac3c7..b85a814776a 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -509,9 +509,7 @@ impl Resolver<'_, '_> { let mut check_redundant_imports = FxIndexSet::default(); for module in self.arenas.local_modules().iter() { for (_key, resolution) in self.resolutions(*module).borrow().iter() { - let resolution = resolution.borrow(); - - if let Some(binding) = resolution.best_binding() + if let Some(binding) = resolution.borrow().best_binding() && let NameBindingKind::Import { import, .. } = binding.kind && let ImportKind::Single { id, .. } = import.kind { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 75eed1e9ad3..3af69b28780 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -523,7 +523,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn add_module_candidates( - &mut self, + &self, module: Module<'ra>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool, @@ -1150,7 +1150,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn lookup_import_candidates_from_module<FilterFn>( - &mut self, + &self, lookup_ident: Ident, namespace: Namespace, parent_scope: &ParentScope<'ra>, @@ -2659,10 +2659,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; } - let resolutions = self.resolutions(crate_module).borrow(); let binding_key = BindingKey::new(ident, MacroNS); - let resolution = resolutions.get(&binding_key)?; - let binding = resolution.borrow().binding()?; + let binding = self.resolution(crate_module, binding_key)?.binding()?; let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { return None; }; diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 34d1e9552fd..fe6e5b8e6eb 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -114,9 +114,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { /// including their whole reexport chains. fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { let module = self.r.expect_module(module_id.to_def_id()); - let resolutions = self.r.resolutions(module); - - for (_, name_resolution) in resolutions.borrow().iter() { + for (_, name_resolution) in self.r.resolutions(module).borrow().iter() { let Some(mut binding) = name_resolution.borrow().binding() else { continue; }; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 71cc68af499..f5bc46bf053 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -848,8 +848,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let key = BindingKey::new(ident, ns); - let resolution = - self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. + // `try_borrow_mut` is required to ensure exclusive access, even if the resulting binding + // doesn't need to be mutable. It will fail when there is a cycle of imports, and without + // the exclusive access infinite recursion will crash the compiler with stack overflow. + let resolution = &*self + .resolution_or_default(module, key) + .try_borrow_mut() + .map_err(|_| (Determined, Weak::No))?; // If the primary binding is unusable, search further and return the shadowed glob // binding if it exists. What we really want here is having two separate scopes in diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 986e703c0d2..156df45147f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -334,8 +334,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } /// Define the name or return the existing binding if there is a collision. - /// `update` indicates if the definition is a redefinition of an existing binding. - pub(crate) fn try_define( + pub(crate) fn try_define_local( &mut self, module: Module<'ra>, ident: Ident, @@ -353,7 +352,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.underscore_disambiguator.update(|d| d + 1); module.underscore_disambiguator.get() }); - self.update_resolution(module, key, warn_ambiguity, |this, resolution| { + self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_binding) = resolution.best_binding() { if res == Res::Err && old_binding.res() != Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. @@ -456,7 +455,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. - fn update_resolution<T, F>( + fn update_local_resolution<T, F>( &mut self, module: Module<'ra>, key: BindingKey, @@ -469,7 +468,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t, warn_ambiguity) = { - let resolution = &mut *self.resolution(module, key).borrow_mut(); + let resolution = &mut *self.resolution_or_default(module, key).borrow_mut(); let old_binding = resolution.binding(); let t = f(self, resolution); @@ -497,7 +496,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, *import); - let _ = self.try_define( + let _ = self.try_define_local( import.parent_scope.module, ident, key.ns, @@ -523,11 +522,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { let module = import.parent_scope.module; - let _ = this.try_define(module, target, ns, dummy_binding, false); + let _ = this.try_define_local(module, target, ns, dummy_binding, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); - this.update_resolution(module, key, false, |_, resolution| { + this.update_local_resolution(module, key, false, |_, resolution| { resolution.single_imports.swap_remove(&import); }) } @@ -651,7 +650,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for module in self.arenas.local_modules().iter() { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - let Some(binding) = resolution.best_binding() else { continue }; if let NameBindingKind::Import { import, .. } = binding.kind @@ -903,14 +901,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - this.define_binding(parent, target, ns, imported_binding); + this.define_binding_local(parent, target, ns, imported_binding); PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); - this.update_resolution(parent, key, false, |_, resolution| { + this.update_local_resolution(parent, key, false, |_, resolution| { resolution.single_imports.swap_remove(&import); }); } @@ -1202,41 +1200,39 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); return if all_ns_failed { - let resolutions = match module { - ModuleOrUniformRoot::Module(module) => Some(self.resolutions(module).borrow()), - _ => None, - }; - let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); - let names = resolutions - .filter_map(|(BindingKey { ident: i, .. }, resolution)| { - if i.name == ident.name { - return None; - } // Never suggest the same name - match *resolution.borrow() { - ref resolution - if let Some(name_binding) = resolution.best_binding() => - { - match name_binding.kind { - NameBindingKind::Import { binding, .. } => { - match binding.kind { - // Never suggest the name that has binding error - // i.e., the name that cannot be previously resolved - NameBindingKind::Res(Res::Err) => None, - _ => Some(i.name), + let names = match module { + ModuleOrUniformRoot::Module(module) => { + self.resolutions(module) + .borrow() + .iter() + .filter_map(|(BindingKey { ident: i, .. }, resolution)| { + if i.name == ident.name { + return None; + } // Never suggest the same name + + let resolution = resolution.borrow(); + if let Some(name_binding) = resolution.best_binding() { + match name_binding.kind { + NameBindingKind::Import { binding, .. } => { + match binding.kind { + // Never suggest the name that has binding error + // i.e., the name that cannot be previously resolved + NameBindingKind::Res(Res::Err) => None, + _ => Some(i.name), + } } + _ => Some(i.name), } - _ => Some(i.name), + } else if resolution.single_imports.is_empty() { + None + } else { + Some(i.name) } - } - NameResolution { ref single_imports, .. } - if single_imports.is_empty() => - { - None - } - _ => Some(i.name), - } - }) - .collect::<Vec<Symbol>>(); + }) + .collect() + } + _ => Vec::new(), + }; let lev_suggestion = find_best_match_for_name(&names, ident.name, None).map(|suggestion| { @@ -1517,10 +1513,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let imported_binding = self.import(binding, import); let warn_ambiguity = self .resolution(import.parent_scope.module, key) - .borrow() - .binding() + .and_then(|r| r.binding()) .is_some_and(|binding| binding.warn_ambiguity_recursive()); - let _ = self.try_define( + let _ = self.try_define_local( import.parent_scope.module, key.ident, key.ns, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a3a770502de..ed9622a0d81 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3449,8 +3449,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); - let mut binding = - self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding()); + let mut binding = self.r.resolution(module, key).and_then(|r| r.best_binding()); debug!(?binding); if binding.is_none() { // We could not find the trait item in the correct namespace. @@ -3461,8 +3460,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { _ => ns, }; let key = BindingKey::new(ident, ns); - binding = - self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding()); + binding = self.r.resolution(module, key).and_then(|r| r.best_binding()); debug!(?binding); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 69095942f52..0f0babd4904 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1461,15 +1461,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(mod_path, None, None) { - let resolutions = self.r.resolutions(module).borrow(); - let targets: Vec<_> = resolutions + let targets: Vec<_> = self + .r + .resolutions(module) + .borrow() .iter() .filter_map(|(key, resolution)| { resolution .borrow() .best_binding() .map(|binding| binding.res()) - .and_then(|res| if filter_fn(res) { Some((key, res)) } else { None }) + .and_then(|res| if filter_fn(res) { Some((*key, res)) } else { None }) }) .collect(); if let [target] = targets.as_slice() { @@ -2300,8 +2302,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { return None; } - let resolutions = self.r.resolutions(*module); - let targets = resolutions + let targets = self + .r + .resolutions(*module) .borrow() .iter() .filter_map(|(key, res)| { @@ -2630,7 +2633,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { false } - fn find_module(&mut self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> { + fn find_module(&self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> { let mut result = None; let mut seen_modules = FxHashSet::default(); let root_did = self.r.graph_root.def_id(); @@ -2687,7 +2690,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { result } - fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> { + fn collect_enum_ctors(&self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> { self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| { let mut variants = Vec::new(); enum_module.for_each_child(self.r, |_, ident, _, name_binding| { @@ -2704,7 +2707,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Adds a suggestion for using an enum's variant when an enum is used instead. fn suggest_using_enum_variant( - &mut self, + &self, err: &mut Diag<'_>, source: PathSource<'_, '_, '_>, def_id: DefId, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 27e14e0e62b..8115b87dcae 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -21,7 +21,7 @@ #![recursion_limit = "256"] // tidy-alphabetical-end -use std::cell::{Cell, RefCell}; +use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeSet; use std::fmt; use std::sync::Arc; @@ -656,11 +656,23 @@ impl<'ra> ModuleData<'ra> { } impl<'ra> Module<'ra> { - fn for_each_child<'tcx, R, F>(self, resolver: &mut R, mut f: F) - where - R: AsMut<Resolver<'ra, 'tcx>>, - F: FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), - { + fn for_each_child<'tcx, R: AsRef<Resolver<'ra, 'tcx>>>( + self, + resolver: &R, + mut f: impl FnMut(&R, Ident, Namespace, NameBinding<'ra>), + ) { + for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { + if let Some(binding) = name_resolution.borrow().best_binding() { + f(resolver, key.ident, key.ns, binding); + } + } + } + + fn for_each_child_mut<'tcx, R: AsMut<Resolver<'ra, 'tcx>>>( + self, + resolver: &mut R, + mut f: impl FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), + ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { f(resolver, key.ident, key.ns, binding); @@ -669,10 +681,7 @@ impl<'ra> Module<'ra> { } /// This modifies `self` in place. The traits will be stored in `self.traits`. - fn ensure_traits<'tcx, R>(self, resolver: &mut R) - where - R: AsMut<Resolver<'ra, 'tcx>>, - { + fn ensure_traits<'tcx>(self, resolver: &impl AsRef<Resolver<'ra, 'tcx>>) { let mut traits = self.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); @@ -681,7 +690,7 @@ impl<'ra> Module<'ra> { return; } if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { - collected_traits.push((name, binding, r.as_mut().get_module(def_id))) + collected_traits.push((name, binding, r.as_ref().get_module(def_id))) } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -1340,6 +1349,12 @@ impl<'ra, 'tcx> AsMut<Resolver<'ra, 'tcx>> for Resolver<'ra, 'tcx> { } } +impl<'ra, 'tcx> AsRef<Resolver<'ra, 'tcx>> for Resolver<'ra, 'tcx> { + fn as_ref(&self) -> &Resolver<'ra, 'tcx> { + self + } +} + impl<'tcx> Resolver<'_, 'tcx> { fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { self.opt_feed(node).map(|f| f.key()) @@ -1861,7 +1876,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We don't reject trait aliases (`trait_module == None`) because we don't have access to their // associated items. fn trait_may_have_item( - &mut self, + &self, trait_module: Option<Module<'ra>>, assoc_item: Option<(Symbol, Namespace)>, ) -> bool { @@ -1893,7 +1908,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { import_ids } - fn resolutions(&mut self, module: Module<'ra>) -> &'ra Resolutions<'ra> { + fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { if module.populate_on_access.get() { module.populate_on_access.set(false); self.build_reduced_graph_external(module); @@ -1902,12 +1917,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn resolution( - &mut self, + &self, + module: Module<'ra>, + key: BindingKey, + ) -> Option<Ref<'ra, NameResolution<'ra>>> { + self.resolutions(module).borrow().get(&key).map(|resolution| resolution.borrow()) + } + + fn resolution_or_default( + &self, module: Module<'ra>, key: BindingKey, ) -> &'ra RefCell<NameResolution<'ra>> { - *self - .resolutions(module) + self.resolutions(module) .borrow_mut() .entry(key) .or_insert_with(|| self.arenas.alloc_name_resolution()) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f0225daa09d..b96d9e7dc8e 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -511,7 +511,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn glob_delegation_suffixes( - &mut self, + &self, trait_def_id: DefId, impl_def_id: LocalDefId, ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 85bd8340c3c..ddcdb7bbc18 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -313,6 +313,7 @@ impl Session { || self.opts.unstable_opts.query_dep_graph || self.opts.unstable_opts.dump_mir.is_some() || self.opts.unstable_opts.unpretty.is_some() + || self.prof.is_args_recording_enabled() || self.opts.output_types.contains_key(&OutputType::Mir) || std::env::var_os("RUSTC_LOG").is_some() { diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index c3080875da8..97d1d9c2d2a 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -322,6 +322,7 @@ impl ExpnId { /// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than /// `expn_id.is_descendant_of(ctxt.outer_expn())`. + #[inline] pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt))) } @@ -394,6 +395,7 @@ impl HygieneData { } } + #[inline] fn with<R>(f: impl FnOnce(&mut HygieneData) -> R) -> R { with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut())) } @@ -406,6 +408,7 @@ impl HygieneData { } } + #[inline] fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData { self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID") } @@ -437,23 +440,28 @@ impl HygieneData { } } + #[inline] fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext { self.syntax_context_data[ctxt.0 as usize].opaque } + #[inline] fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque } + #[inline] fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { self.syntax_context_data[ctxt.0 as usize].outer_expn } + #[inline] fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { let data = &self.syntax_context_data[ctxt.0 as usize]; (data.outer_expn, data.outer_transparency) } + #[inline] fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { self.syntax_context_data[ctxt.0 as usize].parent } @@ -718,11 +726,13 @@ impl SyntaxContext { SyntaxContext(raw as u32) } + #[inline] fn from_usize(raw: usize) -> SyntaxContext { SyntaxContext(u32::try_from(raw).unwrap()) } /// Extend a syntax context with a given expansion and transparency. + #[inline] pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) } @@ -743,10 +753,12 @@ impl SyntaxContext { /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the /// invocation of f that created g1. /// Returns the mark that was removed. + #[inline] pub fn remove_mark(&mut self) -> ExpnId { HygieneData::with(|data| data.remove_mark(self).0) } + #[inline] pub fn marks(self) -> Vec<(ExpnId, Transparency)> { HygieneData::with(|data| data.marks(self)) } @@ -776,11 +788,13 @@ impl SyntaxContext { /// ``` /// This returns the expansion whose definition scope we use to privacy check the resolution, /// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope). + #[inline] pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> { HygieneData::with(|data| data.adjust(self, expn_id)) } /// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0. + #[inline] pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> { HygieneData::with(|data| { *self = data.normalize_to_macros_2_0(*self); @@ -901,10 +915,12 @@ impl SyntaxContext { HygieneData::with(|data| data.outer_mark(self)) } + #[inline] pub(crate) fn dollar_crate_name(self) -> Symbol { HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) } + #[inline] pub fn edition(self) -> Edition { HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9b0e009b2cd..dbc67da37b5 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -167,6 +167,7 @@ where } } +#[inline] pub fn with_session_globals<R, F>(f: F) -> R where F: FnOnce(&SessionGlobals) -> R, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs index 58daaa03675..478726fbef6 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs @@ -6,7 +6,7 @@ pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); base.max_atomic_width = Some(128); base.supports_xray = true; - base.features = "+v8a".into(); + base.features = "+v8a,+outline-atomics".into(); base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index f8d793464a9..18f10da8505 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -80,8 +80,11 @@ fn sizedness_constraint_for_ty<'tcx>( fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness, - hir::Node::ImplItem(hir::ImplItem { defaultness, .. }) + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { defaultness, of_trait: Some(_), .. }), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { defaultness, .. }) | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness, node => { bug!("`defaultness` called on {:?}", node); diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index e3c4a793b37..3a00fe89360 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -400,8 +400,12 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => { - let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; - Ok(Ty::new_adt(cx, a_def, args)) + Ok(if a_args.is_empty() { + a + } else { + let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; + if args == a_args { a } else { Ty::new_adt(cx, a_def, args) } + }) } (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)), @@ -515,8 +519,12 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( } (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { - let args = relation.relate_item_args(a_def_id, a_args, b_args)?; - Ok(Ty::new_fn_def(cx, a_def_id, args)) + Ok(if a_args.is_empty() { + a + } else { + let args = relation.relate_item_args(a_def_id, a_args, b_args)?; + if args == a_args { a } else { Ty::new_fn_def(cx, a_def_id, args) } + }) } (ty::FnPtr(a_sig_tys, a_hdr), ty::FnPtr(b_sig_tys, b_hdr)) => { diff --git a/library/Cargo.lock b/library/Cargo.lock index 94155e08398..94720397fdf 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -78,9 +78,9 @@ dependencies = [ [[package]] name = "dlmalloc" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891" +checksum = "fa3a2dbee57b69fbb5dbe852fa9c0925697fb0c7fbcb1593e90e5ffaedf13d51" dependencies = [ "cfg-if", "libc", @@ -90,11 +90,10 @@ dependencies = [ [[package]] name = "fortanix-sgx-abi" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5" +checksum = "5efc85edd5b83e8394f4371dd0da6859dff63dd387dab8568fece6af4cde6f84" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 017c790ecac..9ba7c5bd28a 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -21,9 +21,7 @@ compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features [features] compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] -compiler-builtins-no-asm = ["compiler_builtins/no-asm"] compiler-builtins-no-f16-f128 = ["compiler_builtins/no-f16-f128"] -compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] # Choose algorithms that are optimized for binary size instead of runtime performance diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 8ac6ce2242d..3d57da63683 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -426,8 +426,10 @@ pub macro debug_assert_matches($($arg:tt)*) { #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] #[rustc_diagnostic_item = "matches_macro"] +#[allow_internal_unstable(non_exhaustive_omitted_patterns_lint, stmt_expr_attributes)] macro_rules! matches { ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { + #[allow(non_exhaustive_omitted_patterns)] match $expression { $pattern $(if $guard)? => true, _ => false diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 546f3d91a80..57bea505433 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -563,8 +563,8 @@ impl AtomicBool { /// `align_of::<AtomicBool>() == 1`). /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not - /// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes, - /// without synchronization. + /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different + /// sizes, without synchronization. /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses @@ -1246,7 +1246,7 @@ impl AtomicBool { /// atomic types work with interior mutability. All modifications of an atomic change the value /// through a shared reference, and can do so safely as long as they use atomic operations. Any /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same - /// restriction: operations on it must be atomic. + /// restriction in [Memory model for atomic accesses]. /// /// # Examples /// @@ -1264,6 +1264,8 @@ impl AtomicBool { /// } /// # } /// ``` + /// + /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] @@ -1519,8 +1521,8 @@ impl<T> AtomicPtr<T> { /// can be bigger than `align_of::<*mut T>()`). /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not - /// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes, - /// without synchronization. + /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different + /// sizes, without synchronization. /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses @@ -2488,7 +2490,7 @@ impl<T> AtomicPtr<T> { /// atomic types work with interior mutability. All modifications of an atomic change the value /// through a shared reference, and can do so safely as long as they use atomic operations. Any /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same - /// restriction: operations on it must be atomic. + /// restriction in [Memory model for atomic accesses]. /// /// # Examples /// @@ -2507,6 +2509,8 @@ impl<T> AtomicPtr<T> { /// my_atomic_op(atomic.as_ptr()); /// } /// ``` + /// + /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] @@ -2698,8 +2702,8 @@ macro_rules! atomic_int { }] /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not - /// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes, - /// without synchronization. + /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different + /// sizes, without synchronization. /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses @@ -3620,7 +3624,7 @@ macro_rules! atomic_int { /// atomic types work with interior mutability. All modifications of an atomic change the value /// through a shared reference, and can do so safely as long as they use atomic operations. Any /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same - /// restriction: operations on it must be atomic. + /// restriction in [Memory model for atomic accesses]. /// /// # Examples /// @@ -3640,6 +3644,8 @@ macro_rules! atomic_int { /// } /// # } /// ``` + /// + /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 4cfac9ecc2a..c5bfd1574e2 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -76,6 +76,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(next_index)] +#![feature(non_exhaustive_omitted_patterns_lint)] #![feature(numfmt)] #![feature(pattern)] #![feature(pointer_is_aligned_to)] diff --git a/library/coretests/tests/macros.rs b/library/coretests/tests/macros.rs index 1c6aa90dfbc..50b5eb63e43 100644 --- a/library/coretests/tests/macros.rs +++ b/library/coretests/tests/macros.rs @@ -213,3 +213,9 @@ fn _expression() { } ); } + +#[deny(non_exhaustive_omitted_patterns)] +fn _matches_does_not_trigger_non_exhaustive_omitted_patterns_lint(o: core::sync::atomic::Ordering) { + // Ordering is a #[non_exhaustive] enum from a separate crate + let _m = matches!(o, core::sync::atomic::Ordering::Relaxed); +} diff --git a/library/rustc-std-workspace-alloc/Cargo.toml b/library/rustc-std-workspace-alloc/Cargo.toml index 5a177808d1b..a5b51059119 100644 --- a/library/rustc-std-workspace-alloc/Cargo.toml +++ b/library/rustc-std-workspace-alloc/Cargo.toml @@ -9,6 +9,9 @@ edition = "2024" [lib] path = "lib.rs" +test = false +bench = false +doc = false [dependencies] alloc = { path = "../alloc" } diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml index 1ddc112380f..d68965c6345 100644 --- a/library/rustc-std-workspace-core/Cargo.toml +++ b/library/rustc-std-workspace-core/Cargo.toml @@ -11,6 +11,9 @@ edition = "2024" [lib] path = "lib.rs" +test = false +bench = false +doc = false [dependencies] core = { path = "../core", public = true } diff --git a/library/rustc-std-workspace-std/Cargo.toml b/library/rustc-std-workspace-std/Cargo.toml index f70994e1f88..6079dc85d90 100644 --- a/library/rustc-std-workspace-std/Cargo.toml +++ b/library/rustc-std-workspace-std/Cargo.toml @@ -9,6 +9,9 @@ edition = "2024" [lib] path = "lib.rs" +test = false +bench = false +doc = false [dependencies] std = { path = "../std" } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index ba1e1f5218a..29ab9be0e69 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -63,10 +63,10 @@ rand = { version = "0.9.0", default-features = false, features = ["alloc"] } rand_xorshift = "0.4.0" [target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] -dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] } +dlmalloc = { version = "0.2.10", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] -fortanix-sgx-abi = { version = "0.5.0", features = [ +fortanix-sgx-abi = { version = "0.6.1", features = [ 'rustc-dep-of-std', ], public = true } @@ -97,9 +97,7 @@ backtrace-trace-only = [] panic-unwind = ["dep:panic_unwind"] compiler-builtins-c = ["alloc/compiler-builtins-c"] compiler-builtins-mem = ["alloc/compiler-builtins-mem"] -compiler-builtins-no-asm = ["alloc/compiler-builtins-no-asm"] compiler-builtins-no-f16-f128 = ["alloc/compiler-builtins-no-f16-f128"] -compiler-builtins-mangled-names = ["alloc/compiler-builtins-mangled-names"] llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 6d7d576b32a..9f17ff76445 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -617,7 +617,7 @@ impl Error for JoinPathsError { /// # Unix /// /// - Returns the value of the 'HOME' environment variable if it is set -/// (including to an empty string). +/// (and not an empty string). /// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function /// using the UID of the current user. An empty home directory field returned from the /// `getpwuid_r` function is considered to be a valid value. diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index dea44124f45..5041770faf6 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -267,7 +267,7 @@ pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> { /// Usercall `insecure_time`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] pub fn insecure_time() -> Duration { - let t = unsafe { raw::insecure_time() }; + let t = unsafe { raw::insecure_time().0 }; Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _) } diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 850bdfdf5b5..0e68313cc3e 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -633,7 +633,10 @@ pub fn temp_dir() -> PathBuf { } pub fn home_dir() -> Option<PathBuf> { - return crate::env::var_os("HOME").or_else(|| unsafe { fallback() }).map(PathBuf::from); + return crate::env::var_os("HOME") + .filter(|s| !s.is_empty()) + .or_else(|| unsafe { fallback() }) + .map(PathBuf::from); #[cfg(any( target_os = "android", diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 6075173db47..8cd1e0163a1 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1399,6 +1399,11 @@ where } /// The internal representation of a `Thread` handle +/// +/// We explicitly set the alignment for our guarantee in Thread::into_raw. This +/// allows applications to stuff extra metadata bits into the alignment, which +/// can be rather useful when working with atomics. +#[repr(align(8))] struct Inner { name: Option<ThreadNameString>, id: ThreadId, @@ -1582,7 +1587,8 @@ impl Thread { /// Consumes the `Thread`, returning a raw pointer. /// /// To avoid a memory leak the pointer must be converted - /// back into a `Thread` using [`Thread::from_raw`]. + /// back into a `Thread` using [`Thread::from_raw`]. The pointer is + /// guaranteed to be aligned to at least 8 bytes. /// /// # Examples /// diff --git a/library/std_detect/src/detect/macros.rs b/library/std_detect/src/detect/macros.rs index c2a006d3753..17140e15653 100644 --- a/library/std_detect/src/detect/macros.rs +++ b/library/std_detect/src/detect/macros.rs @@ -131,14 +131,13 @@ macro_rules! features { }; } - #[test] //tidy:skip #[deny(unexpected_cfgs)] #[deny(unfulfilled_lint_expectations)] - fn unexpected_cfgs() { + const _: () = { $( check_cfg_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?); )* - } + }; /// Each variant denotes a position in a bitset for a particular feature. /// diff --git a/library/std_detect/src/detect/os/riscv.rs b/library/std_detect/src/detect/os/riscv.rs index 46b7dd71eb3..dc9a4036d86 100644 --- a/library/std_detect/src/detect/os/riscv.rs +++ b/library/std_detect/src/detect/os/riscv.rs @@ -135,4 +135,5 @@ pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initialize } #[cfg(test)] +#[path = "riscv/tests.rs"] mod tests; diff --git a/library/stdarch/crates/core_arch/src/wasm32/mod.rs b/library/stdarch/crates/core_arch/src/wasm32/mod.rs index 2c4361f1639..60049c73295 100644 --- a/library/stdarch/crates/core_arch/src/wasm32/mod.rs +++ b/library/stdarch/crates/core_arch/src/wasm32/mod.rs @@ -191,6 +191,16 @@ unsafe extern "C-unwind" { // #[cfg_attr(test, assert_instr(throw, TAG = 0, ptr = core::ptr::null_mut()))] #[inline] #[unstable(feature = "wasm_exception_handling_intrinsics", issue = "122465")] +// FIXME: Since this instruction unwinds, `core` built with `-C panic=unwind` +// cannot be linked with `-C panic=abort` programs. But that's not +// entirely supported anyway, because runtimes without EH support won't +// be able to handle `try` blocks in `-C panic=unwind` crates either. +// We ship `-C panic=abort` `core`, so this doesn't affect users +// directly. Resolving this will likely require patching out both `try` +// and `throw` instructions, at which point we can look into whitelisting +// this function in the compiler to allow linking. +// See https://github.com/rust-lang/rust/issues/118168. +#[allow(ffi_unwind_calls)] pub unsafe fn throw<const TAG: i32>(ptr: *mut u8) -> ! { static_assert!(TAG == 0); // LLVM only supports tag 0 == C++ right now. wasm_throw(TAG, ptr) diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 032f5272a9c..7b4aeed94e9 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -6,6 +6,8 @@ version = "0.0.0" edition = "2024" [lib] +test = false +bench = false # make sure this crate isn't included in public standard library docs doc = false @@ -23,9 +25,7 @@ backtrace = ["std/backtrace"] backtrace-trace-only = ["std/backtrace-trace-only"] compiler-builtins-c = ["std/compiler-builtins-c"] compiler-builtins-mem = ["std/compiler-builtins-mem"] -compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] compiler-builtins-no-f16-f128 = ["std/compiler-builtins-no-f16-f128"] -compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] debug_refcell = ["std/debug_refcell"] llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] diff --git a/library/windows_targets/Cargo.toml b/library/windows_targets/Cargo.toml index 705c9e04381..1c804a0ab39 100644 --- a/library/windows_targets/Cargo.toml +++ b/library/windows_targets/Cargo.toml @@ -4,6 +4,11 @@ description = "A drop-in replacement for the real windows-targets crate for use version = "0.0.0" edition = "2024" +[lib] +test = false +bench = false +doc = false + [features] # Enable using raw-dylib for Windows imports. # This will eventually be the default. diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index 9e82e6a7200..3446e2113dd 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -34,22 +34,12 @@ pub macro link_dylib { #[cfg(feature = "windows_raw_dylib")] pub macro link($($tt:tt)*) { - $crate::link_raw_dylib!($($tt)*) + $crate::link_raw_dylib!($($tt)*); } #[cfg(not(feature = "windows_raw_dylib"))] -pub macro link { - ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( - // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't - // have in this repo. So instead we always link kernel32.lib and add the rest of the import - // libraries below by using an empty extern block. This works because extern blocks are not - // connected to the library given in the #[link] attribute. - #[link(name = "kernel32")] - unsafe extern $abi { - $(#[link_name=$link_name])? - pub fn $($function)*; - } - ) +pub macro link($($tt:tt)*) { + $crate::link_dylib!($($tt)*); } #[cfg(not(feature = "windows_raw_dylib"))] diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index a0371eb7155..b119f2dc3ce 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -19,6 +19,7 @@ const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[ "too_many_arguments", "needless_lifetimes", // people want to keep the lifetimes "wrong_self_convention", + "approx_constant", // libcore is what defines those ]; fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str]) -> Vec<String> { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c7e7b0160b1..4abfe1843eb 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -597,11 +597,6 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car let mut features = String::new(); - if stage != 0 && builder.config.default_codegen_backend(target).as_deref() == Some("cranelift") - { - features += "compiler-builtins-no-f16-f128 "; - } - if builder.no_std(target) == Some(true) { features += " compiler-builtins-mem"; if !target.starts_with("bpf") { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ebbb569e9db..0f9268097d7 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3132,7 +3132,11 @@ impl Step for Bootstrap { } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/bootstrap") + // Bootstrap tests might not be perfectly self-contained and can depend on the external + // environment, submodules that are checked out, etc. + // Therefore we only run them by default on CI. + let runs_on_ci = run.builder.config.is_running_on_ci; + run.path("src/bootstrap").default_condition(runs_on_ci) } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index b39d464493e..15e04f59129 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -338,12 +338,6 @@ than building it. // Make sure musl-root is valid. if target.contains("musl") && !target.contains("unikraft") { - // If this is a native target (host is also musl) and no musl-root is given, - // fall back to the system toolchain in /usr before giving up - if build.musl_root(*target).is_none() && build.config.is_host_target(*target) { - let target = build.config.target_config.entry(*target).or_default(); - target.musl_root = Some("/usr".into()); - } match build.musl_libdir(*target) { Some(libdir) => { if fs::metadata(libdir.join("libc.a")).is_err() { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 63aab4d116a..51a84ad5272 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1329,23 +1329,33 @@ impl Build { } } - /// Returns the "musl root" for this `target`, if defined + /// Returns the "musl root" for this `target`, if defined. + /// + /// If this is a native target (host is also musl) and no musl-root is given, + /// it falls back to the system toolchain in /usr. fn musl_root(&self, target: TargetSelection) -> Option<&Path> { - self.config + let configured_root = self + .config .target_config .get(&target) .and_then(|t| t.musl_root.as_ref()) .or(self.config.musl_root.as_ref()) - .map(|p| &**p) + .map(|p| &**p); + + if self.config.is_host_target(target) && configured_root.is_none() { + Some(Path::new("/usr")) + } else { + configured_root + } } /// Returns the "musl libdir" for this `target`. fn musl_libdir(&self, target: TargetSelection) -> Option<PathBuf> { - let t = self.config.target_config.get(&target)?; - if let libdir @ Some(_) = &t.musl_libdir { - return libdir.clone(); - } - self.musl_root(target).map(|root| root.join("lib")) + self.config + .target_config + .get(&target) + .and_then(|t| t.musl_libdir.clone()) + .or_else(|| self.musl_root(target).map(|root| root.join("lib"))) } /// Returns the `lib` directory for the WASI target specified, if diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index f802640a42d..4b0c4821364 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -439,7 +439,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { change_id: 143255, severity: ChangeSeverity::Warning, - summary: "`llvm.lld` is no longer enabled by default for the dist profile.", + summary: "`rust.lld` is no longer enabled by default for the dist profile.", }, ChangeInfo { change_id: 143251, diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 9c6b4a7615d..9428e221f41 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -1,14 +1,18 @@ //! This module serves two purposes: -//! 1. It is part of the `utils` module and used in other parts of bootstrap. -//! 2. It is embedded inside bootstrap shims to avoid a dependency on the bootstrap library. -//! Therefore, this module should never use any other bootstrap module. This reduces binary -//! size and improves compilation time by minimizing linking time. +//! +//! 1. It is part of the `utils` module and used in other parts of bootstrap. +//! 2. It is embedded inside bootstrap shims to avoid a dependency on the bootstrap library. +//! Therefore, this module should never use any other bootstrap module. This reduces binary size +//! and improves compilation time by minimizing linking time. + +// # Note on tests +// +// If we were to declare a tests submodule here, the shim binaries that include this module via +// `#[path]` would fail to find it, which breaks `./x check bootstrap`. So instead the unit tests +// for this module are in `super::tests::shared_helpers_tests`. #![allow(dead_code)] -#[cfg(test)] -mod tests; - use std::env; use std::ffi::OsString; use std::fs::OpenOptions; @@ -16,10 +20,6 @@ use std::io::Write; use std::process::Command; use std::str::FromStr; -// If we were to declare a tests submodule here, the shim binaries that include this -// module via `#[path]` would fail to find it, which breaks `./x check bootstrap`. -// So instead the unit tests for this module are in `super::tests::shared_helpers_tests`. - /// Returns the environment variable which the dynamic library lookup path /// resides in for this platform. pub fn dylib_path_var() -> &'static str { diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index ec87e71e0b6..983680b0385 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -12,6 +12,10 @@ use crate::{Build, Config, Flags, t}; pub mod git; +// Note: tests for `shared_helpers` is separate here, as otherwise shim binaries that include the +// `shared_helpers` via `#[path]` would fail to find it, breaking `./x check bootstrap`. +mod shared_helpers_tests; + /// Holds temporary state of a bootstrap test. /// Right now it is only used to redirect the build directory of the bootstrap /// invocation, in the future it would be great if we could actually execute diff --git a/src/bootstrap/src/utils/shared_helpers/tests.rs b/src/bootstrap/src/utils/tests/shared_helpers_tests.rs index 559e9f70abd..c486e65007e 100644 --- a/src/bootstrap/src/utils/shared_helpers/tests.rs +++ b/src/bootstrap/src/utils/tests/shared_helpers_tests.rs @@ -1,3 +1,10 @@ +//! The `shared_helpers` module can't have its own tests submodule, because that would cause +//! problems for the shim binaries that include it via `#[path]`, so instead those unit tests live +//! here. +//! +//! To prevent tidy from complaining about this file not being named `tests.rs`, it lives inside a +//! submodule directory named `tests`. + use crate::utils::shared_helpers::parse_value_from_args; #[test] diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile index d3c3cd1b63e..f7d51fba861 100644 --- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile @@ -40,6 +40,7 @@ COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/ # We disable optimized compiler built-ins because that requires a C toolchain for the target. # We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs. ENV SCRIPT \ + python3 ../x.py check bootstrap && \ /scripts/check-default-config-profiles.sh && \ python3 ../x.py build src/tools/build-manifest && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 4d09bea69c0..662a26400ce 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -79,7 +79,6 @@ ENV MUSL_TARGETS=x86_64-unknown-linux-musl \ CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++ ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS -COPY host-x86_64/test-various/uefi_qemu_test /uefi_qemu_test ENV UEFI_TARGETS=aarch64-unknown-uefi,i686-unknown-uefi,x86_64-unknown-uefi \ CC_aarch64_unknown_uefi=clang-11 \ CXX_aarch64_unknown_uefi=clang++-11 \ @@ -88,6 +87,8 @@ ENV UEFI_TARGETS=aarch64-unknown-uefi,i686-unknown-uefi,x86_64-unknown-uefi \ CC_x86_64_unknown_uefi=clang-11 \ CXX_x86_64_unknown_uefi=clang++-11 ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_TARGETS && \ - python3 -u /uefi_qemu_test/run.py + python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target aarch64-unknown-uefi && \ + python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target i686-unknown-uefi && \ + python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target x86_64-unknown-uefi ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py deleted file mode 100755 index 4f877389fbc..00000000000 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python3 - -import os -import shutil -import subprocess -import sys -import tempfile - -from pathlib import Path - -TARGET_AARCH64 = "aarch64-unknown-uefi" -TARGET_I686 = "i686-unknown-uefi" -TARGET_X86_64 = "x86_64-unknown-uefi" - - -def run(*cmd, capture=False, check=True, env=None, timeout=None): - """Print and run a command, optionally capturing the output.""" - cmd = [str(p) for p in cmd] - print(" ".join(cmd)) - return subprocess.run( - cmd, capture_output=capture, check=check, env=env, text=True, timeout=timeout - ) - - -def build_and_run(tmp_dir, target): - if target == TARGET_AARCH64: - boot_file_name = "bootaa64.efi" - ovmf_dir = Path("/usr/share/AAVMF") - ovmf_code = "AAVMF_CODE.fd" - ovmf_vars = "AAVMF_VARS.fd" - qemu = "qemu-system-aarch64" - machine = "virt" - cpu = "cortex-a72" - elif target == TARGET_I686: - boot_file_name = "bootia32.efi" - ovmf_dir = Path("/usr/share/OVMF") - ovmf_code = "OVMF32_CODE_4M.secboot.fd" - ovmf_vars = "OVMF32_VARS_4M.fd" - # The i686 target intentionally uses 64-bit qemu; the important - # difference is that the OVMF code provides a 32-bit environment. - qemu = "qemu-system-x86_64" - machine = "q35" - cpu = "qemu64" - elif target == TARGET_X86_64: - boot_file_name = "bootx64.efi" - ovmf_dir = Path("/usr/share/OVMF") - ovmf_code = "OVMF_CODE.fd" - ovmf_vars = "OVMF_VARS.fd" - qemu = "qemu-system-x86_64" - machine = "q35" - cpu = "qemu64" - else: - raise KeyError("invalid target") - - host_artifacts = Path("/checkout/obj/build/x86_64-unknown-linux-gnu") - stage0 = host_artifacts / "stage0/bin" - stage2 = host_artifacts / "stage2/bin" - - env = dict(os.environ) - env["PATH"] = "{}:{}:{}".format(stage2, stage0, env["PATH"]) - - # Copy the test create into `tmp_dir`. - test_crate = Path(tmp_dir) / "uefi_qemu_test" - shutil.copytree("/uefi_qemu_test", test_crate) - - # Build the UEFI executable. - run( - "cargo", - "build", - "--manifest-path", - test_crate / "Cargo.toml", - "--target", - target, - env=env, - ) - - # Create a mock EFI System Partition in a subdirectory. - esp = test_crate / "esp" - boot = esp / "efi/boot" - os.makedirs(boot, exist_ok=True) - - # Copy the executable into the ESP. - src_exe_path = test_crate / "target" / target / "debug/uefi_qemu_test.efi" - shutil.copy(src_exe_path, boot / boot_file_name) - print(src_exe_path, boot / boot_file_name) - - # Select the appropriate EDK2 build. - ovmf_code = ovmf_dir / ovmf_code - ovmf_vars = ovmf_dir / ovmf_vars - - # Make a writable copy of the vars file. aarch64 doesn't boot - # correctly with read-only vars. - ovmf_rw_vars = Path(tmp_dir) / "vars.fd" - shutil.copy(ovmf_vars, ovmf_rw_vars) - - # Run the executable in QEMU and capture the output. - output = run( - qemu, - "-machine", - machine, - "-cpu", - cpu, - "-display", - "none", - "-serial", - "stdio", - "-drive", - f"if=pflash,format=raw,readonly=on,file={ovmf_code}", - "-drive", - f"if=pflash,format=raw,readonly=off,file={ovmf_rw_vars}", - "-drive", - f"format=raw,file=fat:rw:{esp}", - capture=True, - check=True, - # Set a timeout to kill the VM in case something goes wrong. - timeout=60, - ).stdout - - if "Hello World!" in output: - print("VM produced expected output") - else: - print("unexpected VM output:") - print("---start---") - print(output) - print("---end---") - sys.exit(1) - - -def main(): - targets = [TARGET_AARCH64, TARGET_I686, TARGET_X86_64] - - for target in targets: - # Create a temporary directory so that we have a writeable - # workspace. - with tempfile.TemporaryDirectory() as tmp_dir: - build_and_run(tmp_dir, target) - - -if __name__ == "__main__": - main() diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index f6b7efe51a1..ce9f984e637 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -460259d14de0274b97b8801e08cb2fe5f16fdac5 +efd420c770bb179537c01063e98cb6990c439654 diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index ecc65b26ab7..5fb7eeee8e3 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -40,27 +40,24 @@ implement a new tool feature or test, that should happen in one collective rustc * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh)) * `rustfmt` * `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7)) -* Using the [josh] tool - * `miri` ([sync guide](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo)) - * `rust-analyzer` ([sync script](https://github.com/rust-lang/rust-analyzer/blob/2e13684be123eca7181aa48e043e185d8044a84a/xtask/src/release.rs#L147)) - * `rustc-dev-guide` ([josh sync](#synchronizing-a-josh-subtree)) - * `compiler-builtins` ([josh sync](#synchronizing-a-josh-subtree)) - * `stdarch` ([josh sync](#synchronizing-a-josh-subtree)) +* Using the [josh](#synchronizing-a-josh-subtree) tool + * `miri` + * `rust-analyzer` + * `rustc-dev-guide` + * `compiler-builtins` + * `stdarch` ### Josh subtrees -The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh; you can check out the `miri` or `rust-analyzer` scripts linked above for inspiration. We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). +The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh. We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). ### Synchronizing a Josh subtree We use a dedicated tool called [`rustc-josh-sync`][josh-sync] for performing Josh subtree updates. -Currently, we are migrating Josh repositories to it. So far, it is used in: +The commands below can be used for all our Josh subtrees, although note that `miri` +requires you to perform some [additional steps](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo) during pulls. -- compiler-builtins -- rustc-dev-guide -- stdarch - -To install the tool: +You can install the tool using the following command: ``` cargo install --locked --git https://github.com/rust-lang/josh-sync ``` @@ -80,6 +77,9 @@ switch to its repository checkout directory in your terminal). #### Performing push +> NOTE: +> Before you proceed, look at some guidance related to Git [on josh-sync README]. + 1) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account ``` rustc-josh-sync push <branch-name> <gh-username> @@ -173,3 +173,4 @@ the week leading up to the beta cut. [Toolstate chapter]: https://forge.rust-lang.org/infra/toolstate.html [josh]: https://josh-project.github.io/josh/intro.html [josh-sync]: https://github.com/rust-lang/josh-sync +[on josh-sync README]: https://github.com/rust-lang/josh-sync#git-peculiarities diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1265a39d27b..14295ce0a31 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -36,6 +36,7 @@ use std::mem; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; use rustc_errors::codes::*; use rustc_errors::{FatalError, struct_span_code_err}; @@ -987,28 +988,17 @@ fn clean_proc_macro<'tcx>( kind: MacroKind, cx: &mut DocContext<'tcx>, ) -> ItemKind { - let attrs = cx.tcx.hir_attrs(item.hir_id()); - if kind == MacroKind::Derive - && let Some(derive_name) = - hir_attr_lists(attrs, sym::proc_macro_derive).find_map(|mi| mi.ident()) - { - *name = derive_name.name; + if kind != MacroKind::Derive { + return ProcMacroItem(ProcMacro { kind, helpers: vec![] }); } + let attrs = cx.tcx.hir_attrs(item.hir_id()); + let Some((trait_name, helper_attrs)) = find_attr!(attrs, AttributeKind::ProcMacroDerive { trait_name, helper_attrs, ..} => (*trait_name, helper_attrs)) + else { + return ProcMacroItem(ProcMacro { kind, helpers: vec![] }); + }; + *name = trait_name; + let helpers = helper_attrs.iter().copied().collect(); - let mut helpers = Vec::new(); - for mi in hir_attr_lists(attrs, sym::proc_macro_derive) { - if !mi.has_name(sym::attributes) { - continue; - } - - if let Some(list) = mi.meta_item_list() { - for inner_mi in list { - if let Some(ident) = inner_mi.ident() { - helpers.push(ident.name); - } - } - } - } ProcMacroItem(ProcMacro { kind, helpers }) } @@ -1021,17 +1011,16 @@ fn clean_fn_or_proc_macro<'tcx>( cx: &mut DocContext<'tcx>, ) -> ItemKind { let attrs = cx.tcx.hir_attrs(item.hir_id()); - let macro_kind = attrs.iter().find_map(|a| { - if a.has_name(sym::proc_macro) { - Some(MacroKind::Bang) - } else if a.has_name(sym::proc_macro_derive) { - Some(MacroKind::Derive) - } else if a.has_name(sym::proc_macro_attribute) { - Some(MacroKind::Attr) - } else { - None - } - }); + let macro_kind = if find_attr!(attrs, AttributeKind::ProcMacro(..)) { + Some(MacroKind::Bang) + } else if find_attr!(attrs, AttributeKind::ProcMacroDerive { .. }) { + Some(MacroKind::Derive) + } else if find_attr!(attrs, AttributeKind::ProcMacroAttribute(..)) { + Some(MacroKind::Attr) + } else { + None + }; + match macro_kind { Some(kind) => clean_proc_macro(item, name, kind, cx), None => { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 986390dbaa0..57456e906de 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -173,6 +173,9 @@ pub(crate) struct Options { /// Arguments to be used when compiling doctests. pub(crate) doctest_build_args: Vec<String>, + + /// Target modifiers. + pub(crate) target_modifiers: BTreeMap<OptionsTargetModifiers, String>, } impl fmt::Debug for Options { @@ -846,6 +849,7 @@ impl Options { unstable_features, expanded_args: args, doctest_build_args, + target_modifiers, }; let render_options = RenderOptions { output, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index bd57bb21e63..e89733b2f6d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -214,6 +214,7 @@ pub(crate) fn create_config( scrape_examples_options, expanded_args, remap_path_prefix, + target_modifiers, .. }: RustdocOptions, render_options: &RenderOptions, @@ -277,6 +278,7 @@ pub(crate) fn create_config( } else { OutputTypes::new(&[]) }, + target_modifiers, ..Options::default() }; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 3c4af0dc612..8e3d07b3a1c 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -568,7 +568,11 @@ function preLoadCss(cssUrl) { break; case "-": ev.preventDefault(); - collapseAllDocs(); + collapseAllDocs(false); + break; + case "_": + ev.preventDefault(); + collapseAllDocs(true); break; case "?": @@ -1038,11 +1042,14 @@ function preLoadCss(cssUrl) { innerToggle.children[0].innerText = "Summary"; } - function collapseAllDocs() { + /** + * @param {boolean} collapseImpls - also collapse impl blocks if set to true + */ + function collapseAllDocs(collapseImpls) { const innerToggle = document.getElementById(toggleAllDocsId); addClass(innerToggle, "will-expand"); onEachLazy(document.getElementsByClassName("toggle"), e => { - if (e.parentNode.id !== "implementations-list" || + if ((collapseImpls || e.parentNode.id !== "implementations-list") || (!hasClass(e, "implementors-toggle") && !hasClass(e, "type-contents-toggle")) ) { @@ -1053,7 +1060,10 @@ function preLoadCss(cssUrl) { innerToggle.children[0].innerText = "Show all"; } - function toggleAllDocs() { + /** + * @param {MouseEvent=} ev + */ + function toggleAllDocs(ev) { const innerToggle = document.getElementById(toggleAllDocsId); if (!innerToggle) { return; @@ -1061,7 +1071,7 @@ function preLoadCss(cssUrl) { if (hasClass(innerToggle, "will-expand")) { expandAllDocs(); } else { - collapseAllDocs(); + collapseAllDocs(ev !== undefined && ev.shiftKey); } } @@ -1519,6 +1529,10 @@ function preLoadCss(cssUrl) { ["⏎", "Go to active search result"], ["+", "Expand all sections"], ["-", "Collapse all sections"], + // for the sake of brevity, we don't say "inherint impl blocks", + // although that would be more correct, + // since trait impl blocks are collapsed by - + ["_", "Collapse all sections, including impl blocks"], ].map(x => "<dt>" + x[0].split(" ") .map((y, index) => ((index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " ")) diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 76113726894..ca13b891638 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -418,7 +418,9 @@ class RustdocToolbarElement extends HTMLElement { <div id="help-button" tabindex="-1"> <a href="${rootPath}help.html"><span class="label">Help</span></a> </div> - <button id="toggle-all-docs"><span class="label">Summary</span></button>`; + <button id="toggle-all-docs" +title="Collapse sections (shift-click to also collapse impl blocks)"><span +class="label">Summary</span></button>`; } } window.customElements.define("rustdoc-toolbar", RustdocToolbarElement); diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 6833aa715d724437dc1247d0166afe314ab6854 +Subproject 9b296973b425ffb159e12cf3cd56580fd5c8538 diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml index 7ad58af77d4..ec59be3e7f6 100644 --- a/src/tools/clippy/.github/workflows/feature_freeze.yml +++ b/src/tools/clippy/.github/workflows/feature_freeze.yml @@ -20,16 +20,26 @@ jobs: # of the pull request, as malicious code would be able to access the private # GitHub token. steps: - - name: Check PR Changes - id: pr-changes - run: echo "::set-output name=changes::${{ toJson(github.event.pull_request.changed_files) }}" - - - name: Create Comment - if: steps.pr-changes.outputs.changes != '[]' - run: | - # Use GitHub API to create a comment on the PR - PR_NUMBER=${{ github.event.pull_request.number }} - COMMENT="**Seems that you are trying to add a new lint!**\nWe are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to September 18 and focusing on bugfixes.\nThanks a lot for your contribution, and sorry for the inconvenience.\nWith ❤ from the Clippy team\n\n@rustbot note Feature-freeze\n@rustbot blocked\n@rustbot label +A-lint\n" - GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} - COMMENT_URL="https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" - curl -s -H "Authorization: token ${GITHUB_TOKEN}" -X POST $COMMENT_URL -d "{\"body\":\"$COMMENT\"}" + - name: Add freeze warning comment + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + COMMENT=$(echo "**Seems that you are trying to add a new lint!**\n\ + \n\ + We are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to September 18 and [focusing on bugfixes](https://github.com/rust-lang/rust-clippy/issues/15086).\n\ + \n\ + Thanks a lot for your contribution, and sorry for the inconvenience.\n\ + \n\ + With ❤ from the Clippy team.\n\ + \n\ + @rustbot note Feature-freeze\n\ + @rustbot blocked\n\ + @rustbot label +A-lint" + ) + curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Content-Type: application/vnd.github.raw+json" \ + -X POST \ + --data "{\"body\":\"${COMMENT}\"}" \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" diff --git a/src/tools/clippy/.gitignore b/src/tools/clippy/.gitignore index a7c25b29021..36a4cdc1c35 100644 --- a/src/tools/clippy/.gitignore +++ b/src/tools/clippy/.gitignore @@ -19,8 +19,10 @@ out # Generated by Cargo *Cargo.lock +!/clippy_test_deps/Cargo.lock /target /clippy_lints/target +/clippy_lints_internal/target /clippy_utils/target /clippy_dev/target /lintcheck/target diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs index bd9e57c9f6d..2b2138d3108 100644 --- a/src/tools/clippy/clippy_dev/src/fmt.rs +++ b/src/tools/clippy/clippy_dev/src/fmt.rs @@ -3,7 +3,7 @@ use crate::utils::{ walk_dir_no_dot_or_target, }; use itertools::Itertools; -use rustc_lexer::{TokenKind, tokenize}; +use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use std::fmt::Write; use std::fs; use std::io::{self, Read}; @@ -92,7 +92,7 @@ fn fmt_conf(check: bool) -> Result<(), Error> { let mut fields = Vec::new(); let mut state = State::Start; - for (i, t) in tokenize(conf) + for (i, t) in tokenize(conf, FrontmatterAllowed::No) .map(|x| { let start = pos; pos += x.len; diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 5ed4c82634a..184fbbf7796 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -92,9 +92,11 @@ impl LateLintPass<'_> for ApproxConstant { impl ApproxConstant { fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol, module: &str) { let s = s.as_str(); - if s.parse::<f64>().is_ok() { + if let Ok(maybe_constant) = s.parse::<f64>() { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { - if is_approx_const(constant, s, min_digits) && msrv.is_none_or(|msrv| self.msrv.meets(cx, msrv)) { + if is_approx_const(constant, s, maybe_constant, min_digits) + && msrv.is_none_or(|msrv| self.msrv.meets(cx, msrv)) + { span_lint_and_help( cx, APPROX_CONSTANT, @@ -112,18 +114,35 @@ impl ApproxConstant { impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); +fn count_digits_after_dot(input: &str) -> usize { + input + .char_indices() + .find(|(_, ch)| *ch == '.') + .map_or(0, |(i, _)| input.len() - i - 1) +} + /// Returns `false` if the number of significant figures in `value` are /// less than `min_digits`; otherwise, returns true if `value` is equal -/// to `constant`, rounded to the number of digits present in `value`. +/// to `constant`, rounded to the number of significant digits present in `value`. #[must_use] -fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { +fn is_approx_const(constant: f64, value: &str, f_value: f64, min_digits: usize) -> bool { if value.len() <= min_digits { + // The value is not precise enough false - } else if constant.to_string().starts_with(value) { - // The value is a truncated constant + } else if f_value.to_string().len() > min_digits && constant.to_string().starts_with(&f_value.to_string()) { + // The value represents the same value true } else { - let round_const = format!("{constant:.*}", value.len() - 2); + // The value is a truncated constant + + // Print constant with numeric formatting (`0`), with the length of `value` as minimum width + // (`value_len$`), and with the same precision as `value` (`.value_prec$`). + // See https://doc.rust-lang.org/std/fmt/index.html. + let round_const = format!( + "{constant:0value_len$.value_prec$}", + value_len = value.len(), + value_prec = count_digits_after_dot(value) + ); value == round_const } } diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index a9d3015ce5c..7b4cf033674 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -8,11 +8,11 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::is_cfg_test; use rustc_attr_data_structures::AttributeKind; use rustc_hir::{ - Attribute, FieldDef, HirId, IsAuto, ImplItemId, Item, ItemKind, Mod, OwnerId, QPath, TraitItemId, TyKind, - Variant, VariantData, + Attribute, FieldDef, HirId, ImplItemId, IsAuto, Item, ItemKind, Mod, OwnerId, QPath, TraitItemId, TyKind, Variant, + VariantData, }; -use rustc_middle::ty::AssocKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty::AssocKind; use rustc_session::impl_lint_pass; use rustc_span::Ident; @@ -469,13 +469,14 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { /// This is implemented here because `rustc_hir` is not a dependency of /// `clippy_config`. fn convert_assoc_item_kind(cx: &LateContext<'_>, owner_id: OwnerId) -> SourceItemOrderingTraitAssocItemKind { - let kind = cx.tcx.associated_item(owner_id.def_id).kind; - #[allow(clippy::enum_glob_use)] // Very local glob use for legibility. use SourceItemOrderingTraitAssocItemKind::*; + + let kind = cx.tcx.associated_item(owner_id.def_id).kind; + match kind { - AssocKind::Const{..} => Const, - AssocKind::Type {..}=> Type, + AssocKind::Const { .. } => Const, + AssocKind::Type { .. } => Type, AssocKind::Fn { .. } => Fn, } } diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 9e09fb5bb43..085029a744b 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { diag.note(format!( "`Arc<{arg_ty}>` is not `Send` and `Sync` as `{arg_ty}` is {reason}" )); - diag.help("if the `Arc` will not used be across threads replace it with an `Rc`"); + diag.help("if the `Arc` will not be used across threads replace it with an `Rc`"); diag.help(format!( "otherwise make `{arg_ty}` `Send` and `Sync` or consider a wrapper type such as `Mutex`" )); diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 4059f9603c3..b9b5cedb5aa 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -36,6 +36,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { | sym::unused_braces | sym::unused_import_braces | sym::unused_imports + | sym::redundant_imports ) { return; diff --git a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs index 769cc120c95..849de22cfba 100644 --- a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs @@ -59,9 +59,8 @@ fn get_const_name_and_ty_name( pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We allow casts from any function type to any function type. - match cast_to.kind() { - ty::FnDef(..) | ty::FnPtr(..) => return, - _ => { /* continue to checks */ }, + if cast_to.is_fn() { + return; } if let ty::FnDef(def_id, generics) = cast_from.kind() diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs index 55e27a05f3c..c5d9643f56a 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use super::{FN_TO_NUMERIC_CAST, utils}; @@ -13,23 +13,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, return; }; - match cast_from.kind() { - ty::FnDef(..) | ty::FnPtr(..) => { - let mut applicability = Applicability::MaybeIncorrect; + if cast_from.is_fn() { + let mut applicability = Applicability::MaybeIncorrect; - if to_nbits >= cx.tcx.data_layout.pointer_size().bits() && !cast_to.is_usize() { - let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); - span_lint_and_sugg( - cx, - FN_TO_NUMERIC_CAST, - expr.span, - format!("casting function pointer `{from_snippet}` to `{cast_to}`"), - "try", - format!("{from_snippet} as usize"), - applicability, - ); - } - }, - _ => {}, + if to_nbits >= cx.tcx.data_layout.pointer_size().bits() && !cast_to.is_usize() { + let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); + span_lint_and_sugg( + cx, + FN_TO_NUMERIC_CAST, + expr.span, + format!("casting function pointer `{from_snippet}` to `{cast_to}`"), + "try", + format!("{from_snippet} as usize"), + applicability, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs index b22e8f4ee89..43ee91af6e5 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -3,18 +3,17 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use super::FN_TO_NUMERIC_CAST_ANY; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We allow casts from any function type to any function type. - match cast_to.kind() { - ty::FnDef(..) | ty::FnPtr(..) => return, - _ => { /* continue to checks */ }, + if cast_to.is_fn() { + return; } - if let ty::FnDef(..) | ty::FnPtr(..) = cast_from.kind() { + if cast_from.is_fn() { let mut applicability = Applicability::MaybeIncorrect; let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 4da79205e20..9a2e44e07d4 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils}; @@ -12,23 +12,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else { return; }; - match cast_from.kind() { - ty::FnDef(..) | ty::FnPtr(..) => { - let mut applicability = Applicability::MaybeIncorrect; - let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); + if cast_from.is_fn() { + let mut applicability = Applicability::MaybeIncorrect; + let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); - if to_nbits < cx.tcx.data_layout.pointer_size().bits() { - span_lint_and_sugg( - cx, - FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - expr.span, - format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), - "try", - format!("{from_snippet} as usize"), - applicability, - ); - } - }, - _ => {}, + if to_nbits < cx.tcx.data_layout.pointer_size().bits() { + span_lint_and_sugg( + cx, + FN_TO_NUMERIC_CAST_WITH_TRUNCATION, + expr.span, + format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), + "try", + format!("{from_snippet} as usize"), + applicability, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 6f944914b8f..ee0f3fa81c6 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -4,10 +4,9 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind}; -use rustc_hir_pretty::qpath_to_string; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{Span, sym}; use super::PTR_AS_PTR; @@ -74,7 +73,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { let (help, final_suggestion) = if let Some(method) = omit_cast.corresponding_item() { // don't force absolute path - let method = qpath_to_string(&cx.tcx, method); + let method = snippet_with_applicability(cx, qpath_span_without_turbofish(method), "..", &mut app); ("try call directly", format!("{method}{turbofish}()")) } else { let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app); @@ -96,3 +95,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { ); } } + +fn qpath_span_without_turbofish(qpath: &QPath<'_>) -> Span { + if let QPath::Resolved(_, path) = qpath + && let [.., last_ident] = path.segments + && last_ident.args.is_some() + { + return qpath.span().shrink_to_lo().to(last_ident.ident.span); + } + + qpath.span() +} diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index d5d937d9133..518535e8c8b 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -110,7 +110,6 @@ impl CognitiveComplexity { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { let header_span = body_span.with_hi(decl.output.span().lo()); - #[expect(clippy::range_plus_one)] if let Some(range) = header_span.map_range(cx, |_, src, range| { let mut idxs = src.get(range.clone())?.match_indices('|'); Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 27918698cd6..4bd34527d21 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,5 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_note, span_lint_and_then}; +use clippy_utils::higher::has_let_expr; use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; use clippy_utils::ty::{InteriorMut, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr_without_closures; @@ -11,7 +12,7 @@ use clippy_utils::{ use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit}; +use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; @@ -189,24 +190,13 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { } } -/// Checks if the given expression is a let chain. -fn contains_let(e: &Expr<'_>) -> bool { - match e.kind { - ExprKind::Let(..) => true, - ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => { - matches!(lhs.kind, ExprKind::Let(..)) || contains_let(rhs) - }, - _ => false, - } -} - fn lint_if_same_then_else(cx: &LateContext<'_>, conds: &[&Expr<'_>], blocks: &[&Block<'_>]) -> bool { let mut eq = SpanlessEq::new(cx); blocks .array_windows::<2>() .enumerate() .fold(true, |all_eq, (i, &[lhs, rhs])| { - if eq.eq_block(lhs, rhs) && !contains_let(conds[i]) && conds.get(i + 1).is_none_or(|e| !contains_let(e)) { + if eq.eq_block(lhs, rhs) && !has_let_expr(conds[i]) && conds.get(i + 1).is_none_or(|e| !has_let_expr(e)) { span_lint_and_note( cx, IF_SAME_THEN_ELSE, diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 062f7cef3a7..49dd1bb09c6 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -432,6 +432,11 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result { if let ExprKind::Block(block, _) = expr.kind && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + && block + .span + .source_callee() + .and_then(|expr| expr.macro_def_id) + .is_none_or(|did| !self.cx.tcx.is_diagnostic_item(sym::pin_macro, did)) { return ControlFlow::Break(()); } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index d55aeae98ed..23e7c7251cf 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -72,11 +72,11 @@ pub struct DisallowedMacros { // When a macro is disallowed in an early pass, it's stored // and emitted during the late pass. This happens for attributes. - earlies: AttrStorage, + early_macro_cache: AttrStorage, } impl DisallowedMacros { - pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, earlies: AttrStorage) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, early_macro_cache: AttrStorage) -> Self { let (disallowed, _) = create_disallowed_map( tcx, &conf.disallowed_macros, @@ -89,7 +89,7 @@ impl DisallowedMacros { disallowed, seen: FxHashSet::default(), derive_src: None, - earlies, + early_macro_cache, } } @@ -130,7 +130,7 @@ impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); impl LateLintPass<'_> for DisallowedMacros { fn check_crate(&mut self, cx: &LateContext<'_>) { // once we check a crate in the late pass we can emit the early pass lints - if let Some(attr_spans) = self.earlies.clone().0.get() { + if let Some(attr_spans) = self.early_macro_cache.clone().0.get() { for span in attr_spans { self.check(cx, *span, None); } diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 22b781b8929..ea0da0d2467 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1232,7 +1232,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize headers } -#[expect(clippy::range_plus_one)] // inclusive ranges aren't the same type fn looks_like_refdef(doc: &str, range: Range<usize>) -> Option<Range<usize>> { if range.end < range.start { return None; diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs index 4414aebbf9a..f2757407ba5 100644 --- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs @@ -92,8 +92,10 @@ impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VA impl LateLintPass<'_> for EmptyWithBrackets { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + // FIXME: handle `struct $name {}` if let ItemKind::Struct(ident, _, var_data) = &item.kind && !item.span.from_expansion() + && !ident.span.from_expansion() && has_brackets(var_data) && let span_after_ident = item.span.with_lo(ident.span.hi()) && has_no_fields(cx, var_data, span_after_ident) @@ -116,10 +118,12 @@ impl LateLintPass<'_> for EmptyWithBrackets { } fn check_variant(&mut self, cx: &LateContext<'_>, variant: &Variant<'_>) { - // the span of the parentheses/braces - let span_after_ident = variant.span.with_lo(variant.ident.span.hi()); - - if has_no_fields(cx, &variant.data, span_after_ident) { + // FIXME: handle `$name {}` + if !variant.span.from_expansion() + && !variant.ident.span.from_expansion() + && let span_after_ident = variant.span.with_lo(variant.ident.span.hi()) + && has_no_fields(cx, &variant.data, span_after_ident) + { match variant.data { VariantData::Struct { .. } => { // Empty struct variants can be linted immediately diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index db2fea1aae9..fc224fa5f92 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir; use rustc_abi::ExternAbi; -use rustc_hir::{Body, FnDecl, HirId, HirIdSet, Node, Pat, PatKind, intravisit}; use rustc_hir::def::DefKind; +use rustc_hir::{Body, FnDecl, HirId, HirIdSet, Node, Pat, PatKind, intravisit}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; @@ -87,16 +87,14 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { let mut trait_self_ty = None; match cx.tcx.def_kind(parent_id) { // If the method is an impl for a trait, don't warn. - DefKind::Impl { of_trait: true } => { - return - } + DefKind::Impl { of_trait: true } => return, // find `self` ty for this trait if relevant DefKind::Trait => { trait_self_ty = Some(TraitRef::identity(cx.tcx, parent_id.to_def_id()).self_ty()); - } + }, - _ => {} + _ => {}, } let mut v = EscapeDelegate { diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 0288747d6f3..9b627678bd3 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -29,12 +29,6 @@ declare_clippy_lint! { /// Needlessly creating a closure adds code for no benefit /// and gives the optimizer more work. /// - /// ### Known problems - /// If creating the closure inside the closure has a side- - /// effect then moving the closure creation out will change when that side- - /// effect runs. - /// See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details. - /// /// ### Example /// ```rust,ignore /// xs.map(|x| foo(x)) diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 552cd721f4e..fdfcbb540bc 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -64,8 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom { } fn lint_impl_body(cx: &LateContext<'_>, item_def_id: hir::OwnerId, impl_span: Span) { - use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Expr; + use rustc_hir::intravisit::{self, Visitor}; struct FindPanicUnwrap<'a, 'tcx> { lcx: &'a LateContext<'tcx>, @@ -96,10 +96,12 @@ fn lint_impl_body(cx: &LateContext<'_>, item_def_id: hir::OwnerId, impl_span: Sp } } - for impl_item in cx.tcx.associated_items(item_def_id) + for impl_item in cx + .tcx + .associated_items(item_def_id) .filter_by_name_unhygienic_and_kind(sym::from, ty::AssocTag::Fn) { - let impl_item_def_id= impl_item.def_id.expect_local(); + let impl_item_def_id = impl_item.def_id.expect_local(); // check the body for `begin_panic` or `unwrap` let body = cx.tcx.hir_body_owned_by(impl_item_def_id); diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 16c58ecb455..a251f15ba3d 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -17,7 +17,7 @@ use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, FormatPlaceholder, FormatTrait, }; -use rustc_attr_data_structures::RustcVersion; +use rustc_attr_data_structures::{AttributeKind, RustcVersion, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; @@ -30,7 +30,6 @@ use rustc_span::edition::Edition::Edition2021; use rustc_span::{Span, Symbol, sym}; use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext}; -use rustc_attr_data_structures::{AttributeKind, find_attr}; declare_clippy_lint! { /// ### What it does @@ -129,6 +128,7 @@ declare_clippy_lint! { /// # let width = 1; /// # let prec = 2; /// format!("{}", var); + /// format!("{:?}", var); /// format!("{v:?}", v = var); /// format!("{0} {0}", var); /// format!("{0:1$}", var, width); @@ -141,6 +141,7 @@ declare_clippy_lint! { /// # let prec = 2; /// format!("{var}"); /// format!("{var:?}"); + /// format!("{var:?}"); /// format!("{var} {var}"); /// format!("{var:width$}"); /// format!("{var:.prec$}"); @@ -164,7 +165,7 @@ declare_clippy_lint! { /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. #[clippy::version = "1.66.0"] pub UNINLINED_FORMAT_ARGS, - style, + pedantic, "using non-inlined variables in `format!` calls" } @@ -657,7 +658,10 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { }; let selection = SelectionContext::new(&infcx).select(&obligation); let derived = if let Ok(Some(Selection::UserDefined(data))) = selection { - find_attr!(tcx.get_all_attrs(data.impl_def_id), AttributeKind::AutomaticallyDerived(..)) + find_attr!( + tcx.get_all_attrs(data.impl_def_id), + AttributeKind::AutomaticallyDerived(..) + ) } else { false }; diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 85b40ba7419..1da6952eb64 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -9,7 +9,7 @@ use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ - FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemId, Item, ItemKind, PatKind, Path, + FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemId, ImplItemKind, Item, ItemKind, PatKind, Path, PathSegment, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index d959981a83c..b8d0cec5aeb 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -10,7 +10,7 @@ use rustc_span::{Span, sym}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::snippet_indent; use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; @@ -28,6 +28,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> if let hir::ItemKind::Fn { ref sig, body: ref body_id, + ident, .. } = item.kind { @@ -51,8 +52,8 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> sig.decl, cx.tcx.hir_body(*body_id), item.span, + ident.span, item.owner_id, - item.span.with_hi(sig.decl.output.span().hi()), "this function could have a `#[must_use]` attribute", ); } @@ -84,8 +85,8 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp sig.decl, cx.tcx.hir_body(*body_id), item.span, + item.ident.span, item.owner_id, - item.span.with_hi(sig.decl.output.span().hi()), "this method could have a `#[must_use]` attribute", ); } @@ -120,8 +121,8 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr sig.decl, body, item.span, + item.ident.span, item.owner_id, - item.span.with_hi(sig.decl.output.span().hi()), "this method could have a `#[must_use]` attribute", ); } @@ -198,8 +199,8 @@ fn check_must_use_candidate<'tcx>( decl: &'tcx hir::FnDecl<'_>, body: &'tcx hir::Body<'_>, item_span: Span, + ident_span: Span, item_id: hir::OwnerId, - fn_span: Span, msg: &'static str, ) { if has_mutable_arg(cx, body) @@ -208,18 +209,18 @@ fn check_must_use_candidate<'tcx>( || returns_unit(decl) || !cx.effective_visibilities.is_exported(item_id.def_id) || is_must_use_ty(cx, return_ty(cx, item_id)) + || item_span.from_expansion() { return; } - span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| { - if let Some(snippet) = fn_span.get_source_text(cx) { - diag.span_suggestion( - fn_span, - "add the attribute", - format!("#[must_use] {snippet}"), - Applicability::MachineApplicable, - ); - } + span_lint_and_then(cx, MUST_USE_CANDIDATE, ident_span, msg, |diag| { + let indent = snippet_indent(cx, item_span).unwrap_or_default(); + diag.span_suggestion( + item_span.shrink_to_lo(), + "add the attribute", + format!("#[must_use] \n{indent}"), + Applicability::MachineApplicable, + ); }); } diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index 9e94280fc07..7158f9419c1 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -5,7 +5,8 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{ - contains_return, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, path_res, peel_blocks, + contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, + path_res, peel_blocks, }; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -92,6 +93,10 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { expr.span, format!("this could be simplified with `bool::{method_name}`"), |diag| { + if expr_adjustment_requires_coercion(cx, then_arg) { + return; + } + let mut app = Applicability::MachineApplicable; let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app) .maybe_paren() diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index 5d0bd3e8ca3..116d63c3bb1 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -1,10 +1,11 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; +use clippy_utils::{is_in_const_context, is_in_test}; use rustc_attr_data_structures::{RustcVersion, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{Expr, ExprKind, HirId, QPath}; +use rustc_hir::def::DefKind; +use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; @@ -33,15 +34,54 @@ declare_clippy_lint! { /// /// To fix this problem, either increase your MSRV or use another item /// available in your current MSRV. + /// + /// You can also locally change the MSRV that should be checked by Clippy, + /// for example if a feature in your crate (e.g., `modern_compiler`) should + /// allow you to use an item: + /// + /// ```no_run + /// //! This crate has a MSRV of 1.3.0, but we also have an optional feature + /// //! `sleep_well` which requires at least Rust 1.4.0. + /// + /// // When the `sleep_well` feature is set, do not warn for functions available + /// // in Rust 1.4.0 and below. + /// #![cfg_attr(feature = "sleep_well", clippy::msrv = "1.4.0")] + /// + /// use std::time::Duration; + /// + /// #[cfg(feature = "sleep_well")] + /// fn sleep_for_some_time() { + /// std::thread::sleep(Duration::new(1, 0)); // Will not trigger the lint + /// } + /// ``` + /// + /// You can also increase the MSRV in tests, by using: + /// + /// ```no_run + /// // Use a much higher MSRV for tests while keeping the main one low + /// #![cfg_attr(test, clippy::msrv = "1.85.0")] + /// + /// #[test] + /// fn my_test() { + /// // The tests can use items introduced in Rust 1.85.0 and lower + /// // without triggering the `incompatible_msrv` lint. + /// } + /// ``` #[clippy::version = "1.78.0"] pub INCOMPATIBLE_MSRV, suspicious, "ensures that all items used in the crate are available for the current MSRV" } +#[derive(Clone, Copy)] +enum Availability { + FeatureEnabled, + Since(RustcVersion), +} + pub struct IncompatibleMsrv { msrv: Msrv, - is_above_msrv: FxHashMap<DefId, RustcVersion>, + availability_cache: FxHashMap<(DefId, bool), Availability>, check_in_tests: bool, } @@ -51,38 +91,50 @@ impl IncompatibleMsrv { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv, - is_above_msrv: FxHashMap::default(), + availability_cache: FxHashMap::default(), check_in_tests: conf.check_incompatible_msrv_in_tests, } } - fn get_def_id_version(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> RustcVersion { - if let Some(version) = self.is_above_msrv.get(&def_id) { - return *version; + /// Returns the availability of `def_id`, whether it is enabled through a feature or + /// available since a given version (the default being Rust 1.0.0). `needs_const` requires + /// the `const`-stability to be looked up instead of the stability in non-`const` contexts. + fn get_def_id_availability(&mut self, tcx: TyCtxt<'_>, def_id: DefId, needs_const: bool) -> Availability { + if let Some(availability) = self.availability_cache.get(&(def_id, needs_const)) { + return *availability; } - let version = if let Some(version) = tcx - .lookup_stability(def_id) - .and_then(|stability| match stability.level { - StabilityLevel::Stable { - since: StableSince::Version(version), - .. - } => Some(version), - _ => None, - }) { - version + let (feature, stability_level) = if needs_const { + tcx.lookup_const_stability(def_id) + .map(|stability| (stability.feature, stability.level)) + .unzip() + } else { + tcx.lookup_stability(def_id) + .map(|stability| (stability.feature, stability.level)) + .unzip() + }; + let version = if feature.is_some_and(|feature| tcx.features().enabled(feature)) { + Availability::FeatureEnabled + } else if let Some(StableSince::Version(version)) = + stability_level.as_ref().and_then(StabilityLevel::stable_since) + { + Availability::Since(version) + } else if needs_const { + // Fallback to regular stability + self.get_def_id_availability(tcx, def_id, false) } else if let Some(parent_def_id) = tcx.opt_parent(def_id) { - self.get_def_id_version(tcx, parent_def_id) + self.get_def_id_availability(tcx, parent_def_id, needs_const) } else { - RustcVersion { + Availability::Since(RustcVersion { major: 1, minor: 0, patch: 0, - } + }) }; - self.is_above_msrv.insert(def_id, version); + self.availability_cache.insert((def_id, needs_const), version); version } + /// Emit lint if `def_id`, associated with `node` and `span`, is below the current MSRV. fn emit_lint_if_under_msrv(&mut self, cx: &LateContext<'_>, def_id: DefId, node: HirId, span: Span) { if def_id.is_local() { // We don't check local items since their MSRV is supposed to always be valid. @@ -108,18 +160,28 @@ impl IncompatibleMsrv { return; } + let needs_const = cx.enclosing_body.is_some() + && is_in_const_context(cx) + && matches!(cx.tcx.def_kind(def_id), DefKind::AssocFn | DefKind::Fn); + if (self.check_in_tests || !is_in_test(cx.tcx, node)) && let Some(current) = self.msrv.current(cx) - && let version = self.get_def_id_version(cx.tcx, def_id) + && let Availability::Since(version) = self.get_def_id_availability(cx.tcx, def_id, needs_const) && version > current { - span_lint( + span_lint_and_then( cx, INCOMPATIBLE_MSRV, span, format!( - "current MSRV (Minimum Supported Rust Version) is `{current}` but this item is stable since `{version}`" + "current MSRV (Minimum Supported Rust Version) is `{current}` but this item is stable{} since `{version}`", + if needs_const { " in a `const` context" } else { "" }, ), + |diag| { + if is_under_cfg_attribute(cx, node) { + diag.note_once("you may want to conditionally increase the MSRV considered by Clippy using the `clippy::msrv` attribute"); + } + }, ); } } @@ -133,17 +195,38 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { self.emit_lint_if_under_msrv(cx, method_did, expr.hir_id, span); } }, - ExprKind::Call(call, _) => { - // Desugaring into function calls by the compiler will use `QPath::LangItem` variants. Those should - // not be linted as they will not be generated in older compilers if the function is not available, - // and the compiler is allowed to call unstable functions. - if let ExprKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) = call.kind - && let Some(path_def_id) = cx.qpath_res(&qpath, call.hir_id).opt_def_id() - { - self.emit_lint_if_under_msrv(cx, path_def_id, expr.hir_id, call.span); + // Desugaring into function calls by the compiler will use `QPath::LangItem` variants. Those should + // not be linted as they will not be generated in older compilers if the function is not available, + // and the compiler is allowed to call unstable functions. + ExprKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) => { + if let Some(path_def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() { + self.emit_lint_if_under_msrv(cx, path_def_id, expr.hir_id, expr.span); } }, _ => {}, } } + + fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) { + if let hir::TyKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) = hir_ty.kind + && let Some(ty_def_id) = cx.qpath_res(&qpath, hir_ty.hir_id).opt_def_id() + // `CStr` and `CString` have been moved around but have been available since Rust 1.0.0 + && !matches!(cx.tcx.get_diagnostic_name(ty_def_id), Some(sym::cstr_type | sym::cstring_type)) + { + self.emit_lint_if_under_msrv(cx, ty_def_id, hir_ty.hir_id, hir_ty.span); + } + } +} + +/// Heuristic checking if the node `hir_id` is under a `#[cfg()]` or `#[cfg_attr()]` +/// attribute. +fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { + cx.tcx.hir_parent_id_iter(hir_id).any(|id| { + cx.tcx.hir_attrs(id).iter().any(|attr| { + matches!( + attr.ident().map(|ident| ident.name), + Some(sym::cfg_trace | sym::cfg_attr_trace) + ) + }) + }) } diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs index 7a751514b64..a159f615718 100644 --- a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs +++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs @@ -1,13 +1,12 @@ -use crate::methods::method_call; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{peel_blocks, sym}; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{peel_blocks, peel_hir_expr_while, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -43,53 +42,58 @@ declare_clippy_lint! { declare_lint_pass!(IneffectiveOpenOptions => [INEFFECTIVE_OPEN_OPTIONS]); -fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> { - if let [arg] = args - && let ExprKind::Lit(lit) = peel_blocks(arg).kind - && lit.node == LitKind::Bool(true) - { - // The `.` is not included in the span so we cheat a little bit to include it as well. - Some(call_span.with_lo(call_span.lo() - BytePos(1))) - } else { - None - } -} - impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some((sym::open, mut receiver, [_arg], _, _)) = method_call(expr) else { - return; - }; - let receiver_ty = cx.typeck_results().expr_ty(receiver); - match receiver_ty.peel_refs().kind() { - ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::FsOpenOptions, adt.did()) => {}, - _ => return, - } - - let mut append = None; - let mut write = None; + if let ExprKind::MethodCall(name, recv, [_], _) = expr.kind + && name.ident.name == sym::open + && !expr.span.from_expansion() + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::FsOpenOptions) + { + let mut append = false; + let mut write = None; + peel_hir_expr_while(recv, |e| { + if let ExprKind::MethodCall(name, recv, args, call_span) = e.kind + && !e.span.from_expansion() + { + if let [arg] = args + && let ExprKind::Lit(lit) = peel_blocks(arg).kind + && matches!(lit.node, LitKind::Bool(true)) + && !arg.span.from_expansion() + && !lit.span.from_expansion() + { + match name.ident.name { + sym::append => append = true, + sym::write + if let Some(range) = call_span.map_range(cx, |_, text, range| { + if text.get(..range.start)?.ends_with('.') { + Some(range.start - 1..range.end) + } else { + None + } + }) => + { + write = Some(call_span.with_lo(range.start)); + }, + _ => {}, + } + } + Some(recv) + } else { + None + } + }); - while let Some((name, recv, args, _, span)) = method_call(receiver) { - if name == sym::append { - append = index_if_arg_is_boolean(args, span); - } else if name == sym::write { - write = index_if_arg_is_boolean(args, span); + if append && let Some(write_span) = write { + span_lint_and_sugg( + cx, + INEFFECTIVE_OPEN_OPTIONS, + write_span, + "unnecessary use of `.write(true)` because there is `.append(true)`", + "remove `.write(true)`", + String::new(), + Applicability::MachineApplicable, + ); } - receiver = recv; - } - - if let Some(write_span) = write - && append.is_some() - { - span_lint_and_sugg( - cx, - INEFFECTIVE_OPEN_OPTIONS, - write_span, - "unnecessary use of `.write(true)` because there is `.append(true)`", - "remove `.write(true)`", - String::new(), - Applicability::MachineApplicable, - ); } } } diff --git a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs index e79fcec6e6a..f7cdf05359a 100644 --- a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs +++ b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs @@ -52,13 +52,17 @@ impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom { if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) { return; } - for ii in cx.tcx.associated_items(item.owner_id.def_id) + for ii in cx + .tcx + .associated_items(item.owner_id.def_id) .filter_by_name_unhygienic_and_kind(sym::Error, AssocTag::Type) { let ii_ty = cx.tcx.type_of(ii.def_id).instantiate_identity(); if !ii_ty.is_inhabited_from(cx.tcx, ii.def_id, cx.typing_env()) { let mut span = MultiSpan::from_span(cx.tcx.def_span(item.owner_id.to_def_id())); - let ii_ty_span = cx.tcx.hir_node_by_def_id(ii.def_id.expect_local()) + let ii_ty_span = cx + .tcx + .hir_node_by_def_id(ii.def_id.expect_local()) .expect_impl_item() .expect_type() .span; diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 9c91cf68085..95e16aae40f 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::MacroKind; use rustc_span::symbol::Symbol; declare_clippy_lint! { @@ -502,7 +503,8 @@ impl LateLintPass<'_> for ItemNameRepetitions { ); } - if both_are_public && item_camel.len() > mod_camel.len() { + let is_macro_rule = matches!(item.kind, ItemKind::Macro(_, _, MacroKind::Bang)); + if both_are_public && item_camel.len() > mod_camel.len() && !is_macro_rule { let matching = count_match_start(mod_camel, &item_camel); let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 03038f0ab49..b89f91f7255 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -139,11 +139,17 @@ impl LateLintPass<'_> for IterWithoutIntoIter { // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some() }) - && let Some(iter_assoc_span) = cx.tcx.associated_items(item.owner_id) + && let Some(iter_assoc_span) = cx + .tcx + .associated_items(item.owner_id) .filter_by_name_unhygienic_and_kind(sym::IntoIter, ty::AssocTag::Type) .next() .map(|assoc_item| { - cx.tcx.hir_node_by_def_id(assoc_item.def_id.expect_local()).expect_impl_item().expect_type().span + cx.tcx + .hir_node_by_def_id(assoc_item.def_id.expect_local()) + .expect_impl_item() + .expect_type() + .span }) && is_ty_exported(cx, ty) { diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index e85d779b488..c2b73943106 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -1,5 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy}; use rustc_errors::Applicability; @@ -83,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { let mut difference = variants_size[0].size - variants_size[1].size; if difference > self.maximum_size_difference_allowed { - let help_text = "consider boxing the large fields to reduce the total size of the enum"; + let help_text = "consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum"; span_lint_and_then( cx, LARGE_ENUM_VARIANT, @@ -117,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { ident.span, "boxing a variant would require the type no longer be `Copy`", ); - } else { + } else if !is_no_std_crate(cx) { let sugg: Vec<(Span, String)> = variants_size[0] .fields_size .iter() diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index b3c63f022d3..42c636505c0 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -1,7 +1,8 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::{get_parent_expr, is_from_proc_macro}; +use clippy_utils::source::SpanRangeExt; use hir::def_id::DefId; use rustc_errors::Applicability; use rustc_hir as hir; @@ -102,39 +103,45 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - let ExprKind::Path(qpath) = &expr.kind else { - return; - }; - // `std::<integer>::<CONST>` check - let (span, sugg, msg) = if let QPath::Resolved(None, path) = qpath + let (sugg, msg) = if let ExprKind::Path(qpath) = &expr.kind + && let QPath::Resolved(None, path) = qpath && let Some(def_id) = path.res.opt_def_id() && is_numeric_const(cx, def_id) - && let def_path = cx.get_def_path(def_id) - && let [.., mod_name, name] = &*def_path + && let [.., mod_name, name] = &*cx.get_def_path(def_id) // Skip linting if this usage looks identical to the associated constant, // since this would only require removing a `use` import (which is already linted). && !is_numeric_const_path_canonical(path, [*mod_name, *name]) { ( - expr.span, - format!("{mod_name}::{name}"), + vec![(expr.span, format!("{mod_name}::{name}"))], "usage of a legacy numeric constant", ) // `<integer>::xxx_value` check - } else if let QPath::TypeRelative(_, last_segment) = qpath - && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id() - && let Some(par_expr) = get_parent_expr(cx, expr) - && let ExprKind::Call(_, []) = par_expr.kind + } else if let ExprKind::Call(func, []) = &expr.kind + && let ExprKind::Path(qpath) = &func.kind + && let QPath::TypeRelative(ty, last_segment) = qpath + && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() && is_integer_method(cx, def_id) { - let name = last_segment.ident.name.as_str(); - - ( - last_segment.ident.span.with_hi(par_expr.span.hi()), - name[..=2].to_ascii_uppercase(), - "usage of a legacy numeric method", - ) + let mut sugg = vec![ + // Replace the function name up to the end by the constant name + ( + last_segment.ident.span.to(expr.span.shrink_to_hi()), + last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(), + ), + ]; + let before_span = expr.span.shrink_to_lo().until(ty.span); + if !before_span.is_empty() { + // Remove everything before the type name + sugg.push((before_span, String::new())); + } + // Use `::` between the type name and the constant + let between_span = ty.span.shrink_to_hi().until(last_segment.ident.span); + if !between_span.check_source_text(cx, |s| s == "::") { + sugg.push((between_span, String::from("::"))); + } + (sugg, "usage of a legacy numeric method") } else { return; }; @@ -143,9 +150,8 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { && self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS) && !is_from_proc_macro(cx, expr) { - span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { - diag.span_suggestion_verbose( - span, + span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.span, msg, |diag| { + diag.multipart_suggestion_verbose( "use the associated constant instead", sugg, Applicability::MaybeIncorrect, diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 1bf03480c82..6beddc1be14 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -10,9 +10,9 @@ 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, TraitItemId, TyKind, + BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind, ImplicitSelfKind, + Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy, QPath, TraitItemId, + TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FnSig, Ty}; @@ -266,11 +266,14 @@ 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 { + 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, .. })], + [Some(Ident { + name: kw::SelfLower, + .. + })], ) } @@ -284,7 +287,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden } if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id) - && trait_items.iter().any(|i| is_named_self(cx, i, sym::len)) + && 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); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 7837b18bcd3..972b0b110e0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -39,7 +39,9 @@ pub(super) fn check<'tcx>( var: canonical_id, indexed_mut: FxHashSet::default(), indexed_indirectly: FxHashMap::default(), + unnamed_indexed_indirectly: false, indexed_directly: FxIndexMap::default(), + unnamed_indexed_directly: false, referenced: FxHashSet::default(), nonindex: false, prefer_mutable: false, @@ -47,7 +49,11 @@ pub(super) fn check<'tcx>( walk_expr(&mut visitor, body); // linting condition: we only indexed one variable, and indexed it directly - if visitor.indexed_indirectly.is_empty() && visitor.indexed_directly.len() == 1 { + if visitor.indexed_indirectly.is_empty() + && !visitor.unnamed_indexed_indirectly + && !visitor.unnamed_indexed_directly + && visitor.indexed_directly.len() == 1 + { let (indexed, (indexed_extent, indexed_ty)) = visitor .indexed_directly .into_iter() @@ -217,6 +223,7 @@ fn is_end_eq_array_len<'tcx>( false } +#[expect(clippy::struct_excessive_bools)] struct VarVisitor<'a, 'tcx> { /// context reference cx: &'a LateContext<'tcx>, @@ -226,9 +233,13 @@ struct VarVisitor<'a, 'tcx> { indexed_mut: FxHashSet<Symbol>, /// indirectly indexed variables (`v[(i + 4) % N]`), the extend is `None` for global indexed_indirectly: FxHashMap<Symbol, Option<region::Scope>>, + /// indirectly indexed literals, like `[1, 2, 3][(i + 4) % N]` + unnamed_indexed_indirectly: bool, /// subset of `indexed` of vars that are indexed directly: `v[i]` /// this will not contain cases like `v[calc_index(i)]` or `v[(i + 4) % N]` indexed_directly: FxIndexMap<Symbol, (Option<region::Scope>, Ty<'tcx>)>, + /// directly indexed literals, like `[1, 2, 3][i]` + unnamed_indexed_directly: bool, /// Any names that are used outside an index operation. /// Used to detect things like `&mut vec` used together with `vec[i]` referenced: FxHashSet<Symbol>, @@ -242,6 +253,7 @@ struct VarVisitor<'a, 'tcx> { impl<'tcx> VarVisitor<'_, 'tcx> { fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool { + let index_used_directly = matches!(idx.kind, ExprKind::Path(_)); if let ExprKind::Path(ref seqpath) = seqexpr.kind // the indexed container is referenced by a name && let QPath::Resolved(None, seqvar) = *seqpath @@ -251,7 +263,6 @@ impl<'tcx> VarVisitor<'_, 'tcx> { if self.prefer_mutable { self.indexed_mut.insert(seqvar.segments[0].ident.name); } - let index_used_directly = matches!(idx.kind, ExprKind::Path(_)); let res = self.cx.qpath_res(seqpath, seqexpr.hir_id); match res { Res::Local(hir_id) => { @@ -286,6 +297,13 @@ impl<'tcx> VarVisitor<'_, 'tcx> { }, _ => (), } + } else if let ExprKind::Repeat(..) | ExprKind::Array(..) = seqexpr.kind { + if index_used_directly { + self.unnamed_indexed_directly = true; + } else { + self.unnamed_indexed_indirectly = true; + } + return false; } true } diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 69c84bc7038..8a253ae5810 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -6,9 +6,11 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use rustc_errors::Applicability; -use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind, StructTailExpr}; +use rustc_hir::{ + Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Node, Pat, Stmt, StmtKind, StructTailExpr, +}; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::{BytePos, Span, sym}; use std::iter::once; use std::ops::ControlFlow; @@ -20,7 +22,7 @@ pub(super) fn check<'tcx>( for_loop: Option<&ForLoop<'_>>, ) { match never_loop_block(cx, block, &mut Vec::new(), loop_id) { - NeverLoopResult::Diverging => { + NeverLoopResult::Diverging { ref break_spans } => { span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| { if let Some(ForLoop { arg: iterator, @@ -38,10 +40,15 @@ pub(super) fn check<'tcx>( Applicability::Unspecified }; - diag.span_suggestion_verbose( + let mut suggestions = vec![( for_span.with_hi(iterator.span.hi()), - "if you need the first element of the iterator, try writing", for_to_if_let_sugg(cx, iterator, pat), + )]; + // Make sure to clear up the diverging sites when we remove a loopp. + suggestions.extend(break_spans.iter().map(|span| (*span, String::new()))); + diag.multipart_suggestion_verbose( + "if you need the first element of the iterator, try writing", + suggestions, app, ); } @@ -70,22 +77,22 @@ fn contains_any_break_or_continue(block: &Block<'_>) -> bool { /// The first two bits of information are in this enum, and the last part is in the /// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by /// scope. -#[derive(Copy, Clone)] +#[derive(Clone)] enum NeverLoopResult { /// A continue may occur for the main loop. MayContinueMainLoop, /// We have not encountered any main loop continue, /// but we are diverging (subsequent control flow is not reachable) - Diverging, + Diverging { break_spans: Vec<Span> }, /// We have not encountered any main loop continue, /// and subsequent control flow is (possibly) reachable Normal, } #[must_use] -fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult { +fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult { match arg { - NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal, + NeverLoopResult::Diverging { .. } | NeverLoopResult::Normal => NeverLoopResult::Normal, NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop, } } @@ -94,7 +101,7 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult { #[must_use] fn combine_seq(first: NeverLoopResult, second: impl FnOnce() -> NeverLoopResult) -> NeverLoopResult { match first { - NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop => first, + NeverLoopResult::Diverging { .. } | NeverLoopResult::MayContinueMainLoop => first, NeverLoopResult::Normal => second(), } } @@ -103,7 +110,7 @@ fn combine_seq(first: NeverLoopResult, second: impl FnOnce() -> NeverLoopResult) #[must_use] fn combine_seq_many(iter: impl IntoIterator<Item = NeverLoopResult>) -> NeverLoopResult { for e in iter { - if let NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop = e { + if let NeverLoopResult::Diverging { .. } | NeverLoopResult::MayContinueMainLoop = e { return e; } } @@ -118,7 +125,19 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult NeverLoopResult::MayContinueMainLoop }, (NeverLoopResult::Normal, _) | (_, NeverLoopResult::Normal) => NeverLoopResult::Normal, - (NeverLoopResult::Diverging, NeverLoopResult::Diverging) => NeverLoopResult::Diverging, + ( + NeverLoopResult::Diverging { + break_spans: mut break_spans1, + }, + NeverLoopResult::Diverging { + break_spans: mut break_spans2, + }, + ) => { + break_spans1.append(&mut break_spans2); + NeverLoopResult::Diverging { + break_spans: break_spans1, + } + }, } } @@ -136,7 +155,7 @@ fn never_loop_block<'tcx>( combine_seq_many(iter.map(|(e, els)| { let e = never_loop_expr(cx, e, local_labels, main_loop_id); // els is an else block in a let...else binding - els.map_or(e, |els| { + els.map_or(e.clone(), |els| { combine_seq(e, || match never_loop_block(cx, els, local_labels, main_loop_id) { // Returning MayContinueMainLoop here means that // we will not evaluate the rest of the body @@ -144,7 +163,7 @@ fn never_loop_block<'tcx>( // An else block always diverges, so the Normal case should not happen, // but the analysis is approximate so it might return Normal anyway. // Returning Normal here says that nothing more happens on the main path - NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal, + NeverLoopResult::Diverging { .. } | NeverLoopResult::Normal => NeverLoopResult::Normal, }) }) })) @@ -159,6 +178,45 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t } } +fn stmt_source_span(stmt: &Stmt<'_>) -> Span { + let call_span = stmt.span.source_callsite(); + // if it is a macro call, the span will be missing the trailing semicolon + if stmt.span == call_span { + return call_span; + } + + // An expression without a trailing semi-colon (must have unit type). + if let StmtKind::Expr(..) = stmt.kind { + return call_span; + } + + call_span.with_hi(call_span.hi() + BytePos(1)) +} + +/// Returns a Vec of all the individual spans after the highlighted expression in a block +fn all_spans_after_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Vec<Span> { + if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + if let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id) { + return block + .stmts + .iter() + .skip_while(|inner| inner.hir_id != stmt.hir_id) + .map(stmt_source_span) + .chain(if let Some(e) = block.expr { vec![e.span] } else { vec![] }) + .collect(); + } + + return vec![stmt.span]; + } + + vec![] +} + +fn is_label_for_block(cx: &LateContext<'_>, dest: &Destination) -> bool { + dest.target_id + .is_ok_and(|hir_id| matches!(cx.tcx.hir_node(hir_id), Node::Block(_))) +} + #[allow(clippy::too_many_lines)] fn never_loop_expr<'tcx>( cx: &LateContext<'tcx>, @@ -197,7 +255,7 @@ fn never_loop_expr<'tcx>( ExprKind::Loop(b, _, _, _) => { // We don't attempt to track reachability after a loop, // just assume there may have been a break somewhere - absorb_break(never_loop_block(cx, b, local_labels, main_loop_id)) + absorb_break(&never_loop_block(cx, b, local_labels, main_loop_id)) }, ExprKind::If(e, e2, e3) => { let e1 = never_loop_expr(cx, e, local_labels, main_loop_id); @@ -212,9 +270,10 @@ fn never_loop_expr<'tcx>( ExprKind::Match(e, arms, _) => { let e = never_loop_expr(cx, e, local_labels, main_loop_id); combine_seq(e, || { - arms.iter().fold(NeverLoopResult::Diverging, |a, b| { - combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id)) - }) + arms.iter() + .fold(NeverLoopResult::Diverging { break_spans: vec![] }, |a, b| { + combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id)) + }) }) }, ExprKind::Block(b, _) => { @@ -224,7 +283,7 @@ fn never_loop_expr<'tcx>( let ret = never_loop_block(cx, b, local_labels, main_loop_id); let jumped_to = b.targeted_by_break && local_labels.pop().unwrap().1; match ret { - NeverLoopResult::Diverging if jumped_to => NeverLoopResult::Normal, + NeverLoopResult::Diverging { .. } if jumped_to => NeverLoopResult::Normal, _ => ret, } }, @@ -235,25 +294,39 @@ fn never_loop_expr<'tcx>( if id == main_loop_id { NeverLoopResult::MayContinueMainLoop } else { - NeverLoopResult::Diverging + NeverLoopResult::Diverging { + break_spans: all_spans_after_expr(cx, expr), + } } }, - ExprKind::Break(_, e) | ExprKind::Ret(e) => { + ExprKind::Ret(e) => { let first = e.as_ref().map_or(NeverLoopResult::Normal, |e| { never_loop_expr(cx, e, local_labels, main_loop_id) }); combine_seq(first, || { // checks if break targets a block instead of a loop - if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind - && let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) - { - *reachable = true; + mark_block_as_reachable(expr, local_labels); + NeverLoopResult::Diverging { break_spans: vec![] } + }) + }, + ExprKind::Break(dest, e) => { + let first = e.as_ref().map_or(NeverLoopResult::Normal, |e| { + never_loop_expr(cx, e, local_labels, main_loop_id) + }); + combine_seq(first, || { + // checks if break targets a block instead of a loop + mark_block_as_reachable(expr, local_labels); + NeverLoopResult::Diverging { + break_spans: if is_label_for_block(cx, &dest) { + vec![] + } else { + all_spans_after_expr(cx, expr) + }, } - NeverLoopResult::Diverging }) }, ExprKind::Become(e) => combine_seq(never_loop_expr(cx, e, local_labels, main_loop_id), || { - NeverLoopResult::Diverging + NeverLoopResult::Diverging { break_spans: vec![] } }), ExprKind::InlineAsm(asm) => combine_seq_many(asm.operands.iter().map(|(o, _)| match o { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => { @@ -283,12 +356,12 @@ fn never_loop_expr<'tcx>( }; let result = combine_seq(result, || { if cx.typeck_results().expr_ty(expr).is_never() { - NeverLoopResult::Diverging + NeverLoopResult::Diverging { break_spans: vec![] } } else { NeverLoopResult::Normal } }); - if let NeverLoopResult::Diverging = result + if let NeverLoopResult::Diverging { .. } = result && let Some(macro_call) = root_macro_call_first_node(cx, expr) && let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id) { @@ -316,3 +389,11 @@ fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) format!("if let Some({pat_snippet}) = {iter_snippet}.next()") } + +fn mark_block_as_reachable(expr: &Expr<'_>, local_labels: &mut [(HirId, bool)]) { + if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind + && let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) + { + *reachable = true; + } +} diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index d1a54df988f..3aa449f6411 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -1,15 +1,15 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::{self as hir, AmbigArg}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::edition::Edition; -use rustc_span::{Span}; use std::collections::BTreeMap; -use rustc_attr_data_structures::{AttributeKind, find_attr}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs index bac4b3d32f2..288f27db8ca 100644 --- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs +++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs @@ -5,7 +5,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::HasSession as _; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment}; +use clippy_utils::{eq_expr_value, peel_blocks, peel_middle_ty_refs, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAbsDiff { && let ExprKind::Binary(op, rhs, lhs) = if_expr.cond.kind && let (BinOpKind::Gt | BinOpKind::Ge, mut a, mut b) | (BinOpKind::Lt | BinOpKind::Le, mut b, mut a) = (op.node, rhs, lhs) - && let Some(ty) = self.are_ty_eligible(cx, a, b) + && let Some((ty, b_n_refs)) = self.are_ty_eligible(cx, a, b) && is_sub_expr(cx, if_expr.then, a, b, ty) && is_sub_expr(cx, r#else, b, a, ty) { @@ -86,8 +86,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualAbsDiff { } }; let sugg = format!( - "{}.abs_diff({})", + "{}.abs_diff({}{})", Sugg::hir(cx, a, "..").maybe_paren(), + "*".repeat(b_n_refs), Sugg::hir(cx, b, "..") ); diag.span_suggestion(expr.span, "replace with `abs_diff`", sugg, applicability); @@ -100,13 +101,15 @@ impl<'tcx> LateLintPass<'tcx> for ManualAbsDiff { impl ManualAbsDiff { /// Returns a type if `a` and `b` are both of it, and this lint can be applied to that /// type (currently, any primitive int, or a `Duration`) - fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option<Ty<'tcx>> { + fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option<(Ty<'tcx>, usize)> { let is_int = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) && self.msrv.meets(cx, msrvs::ABS_DIFF); let is_duration = |ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF); let a_ty = cx.typeck_results().expr_ty(a).peel_refs(); - (a_ty == cx.typeck_results().expr_ty(b).peel_refs() && (is_int(a_ty) || is_duration(a_ty))).then_some(a_ty) + let (b_ty, b_n_refs) = peel_middle_ty_refs(cx.typeck_results().expr_ty(b)); + + (a_ty == b_ty && (is_int(a_ty) || is_duration(a_ty))).then_some((a_ty, b_n_refs)) } } diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index 8378e15c581..ea6b01a053a 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -60,7 +60,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { ExprKind::Unary(UnOp::Not, e) => (e, ""), _ => (cond, "!"), }; - let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_paren(); + let cond_sugg = + sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability).maybe_paren(); let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" }; let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip}){semicolon}"); // we show to the user the suggestion without the comments, but when applying the fix, include the diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 08c0caa4266..7e530e98ac4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -152,21 +152,26 @@ fn report_single_pattern( }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1, _ => pat_ref_count, }; - // References are only implicitly added to the pattern, so no overflow here. - // e.g. will work: match &Some(_) { Some(_) => () } - // will not: match Some(_) { &Some(_) => () } - let ref_count_diff = ty_ref_count - pat_ref_count; - // Try to remove address of expressions first. - let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff); - let ref_count_diff = ref_count_diff - removed; + // References are implicitly removed when `deref_patterns` are used. + // They are implicitly added when match ergonomics are used. + let (ex, ref_or_deref_adjust) = if ty_ref_count > pat_ref_count { + let ref_count_diff = ty_ref_count - pat_ref_count; + + // Try to remove address of expressions first. + let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff); + + (ex, String::from(if ref_count_diff == removed { "" } else { "&" })) + } else { + (ex, "*".repeat(pat_ref_count - ty_ref_count)) + }; let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`"; let sugg = format!( "if {} == {}{} {}{els_str}", snippet_with_context(cx, ex.span, ctxt, "..", &mut app).0, // PartialEq for different reference counts may not exist. - "&".repeat(ref_count_diff), + ref_or_deref_adjust, snippet_with_applicability(cx, arm.pat.span, "..", &mut app), expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app), ); diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index 82e5a6d5a41..6e5da5bda8c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -2,13 +2,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{contains_return, is_inside_always_const_context, peel_blocks}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::borrow::Cow; +use std::ops::ControlFlow; use super::EXPECT_FUN_CALL; @@ -23,10 +25,10 @@ pub(super) fn check<'tcx>( receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { - // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or + // Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or // `&str` fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - let mut arg_root = arg; + let mut arg_root = peel_blocks(arg); loop { arg_root = match &arg_root.kind { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, @@ -47,124 +49,68 @@ pub(super) fn check<'tcx>( arg_root } - // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be - // converted to string. - fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { - let arg_ty = cx.typeck_results().expr_ty(arg); - if is_type_lang_item(cx, arg_ty, hir::LangItem::String) { - return false; - } - if let ty::Ref(_, ty, ..) = arg_ty.kind() - && ty.is_str() - && can_be_static_str(cx, arg) - { - return false; - } - true + fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool { + for_each_expr(cx, arg, |expr| { + if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. }) + && !is_inside_always_const_context(cx.tcx, expr.hir_id) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() } - // Check if an expression could have type `&'static str`, knowing that it - // has type `&str` for some lifetime. - fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { - match arg.kind { - hir::ExprKind::Lit(_) => true, - hir::ExprKind::Call(fun, _) => { - if let hir::ExprKind::Path(ref p) = fun.kind { - match cx.qpath_res(p, fun.hir_id) { - hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( - cx.tcx.fn_sig(def_id).instantiate_identity().output().skip_binder().kind(), - ty::Ref(re, ..) if re.is_static(), - ), - _ => false, - } - } else { - false - } - }, - hir::ExprKind::MethodCall(..) => { - cx.typeck_results() - .type_dependent_def_id(arg.hir_id) - .is_some_and(|method_id| { - matches!( - cx.tcx.fn_sig(method_id).instantiate_identity().output().skip_binder().kind(), - ty::Ref(re, ..) if re.is_static() - ) - }) - }, - hir::ExprKind::Path(ref p) => matches!( - cx.qpath_res(p, arg.hir_id), - hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static { .. }, _) - ), - _ => false, - } - } + if name == sym::expect + && let [arg] = args + && let arg_root = get_arg_root(cx, arg) + && contains_call(cx, arg_root) + && !contains_return(arg_root) + { + let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver); + let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) { + "||" + } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) { + "|_|" + } else { + return; + }; - fn is_call(node: &hir::ExprKind<'_>) -> bool { - match node { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => { - is_call(&expr.kind) - }, - hir::ExprKind::Call(..) - | hir::ExprKind::MethodCall(..) - // These variants are debatable or require further examination - | hir::ExprKind::If(..) - | hir::ExprKind::Match(..) - | hir::ExprKind::Block{ .. } => true, - _ => false, - } - } + let span_replace_word = method_span.with_hi(expr.span.hi()); - if args.len() != 1 || name != sym::expect || !is_call(&args[0].kind) { - return; - } + let mut applicability = Applicability::MachineApplicable; - let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver); - let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) { - "||" - } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) { - "|_|" - } else { - return; - }; - - let arg_root = get_arg_root(cx, &args[0]); - - let span_replace_word = method_span.with_hi(expr.span.hi()); - - let mut applicability = Applicability::MachineApplicable; - - // Special handling for `format!` as arg_root - if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) { - if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) - && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn) - { - let span = format_args_inputs_span(format_args); - let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - format!("function call inside of `{name}`"), - "try", - format!("unwrap_or_else({closure_args} panic!({sugg}))"), - applicability, - ); + // Special handling for `format!` as arg_root + if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) { + if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) + && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn) + { + let span = format_args_inputs_span(format_args); + let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + format!("function call inside of `{name}`"), + "try", + format!("unwrap_or_else({closure_args} panic!({sugg}))"), + applicability, + ); + } + return; } - return; - } - let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability); - if requires_to_string(cx, arg_root) { - arg_root_snippet.to_mut().push_str(".to_string()"); - } + let arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability); - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - format!("function call inside of `{name}`"), - "try", - format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"), - applicability, - ); + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + format!("function call inside of `{name}`"), + "try", + format!("unwrap_or_else({closure_args} panic!(\"{{}}\", {arg_root_snippet}))"), + applicability, + ); + } } diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 965993808f6..94944bd9445 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,6 +1,6 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::ty::is_copy; use clippy_utils::{ CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, is_trait_method, peel_blocks, @@ -45,9 +45,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count() && let Some(param_snippet) = param.span.get_source_text(cx) - && let Some(filter) = recv.span.get_source_text(cx) - && let Some(map) = then_body.span.get_source_text(cx) { + let mut applicability = Applicability::MachineApplicable; + let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability); + let (map, _) = snippet_with_context(cx, then_body.span, expr.span.ctxt(), "..", &mut applicability); + span_lint_and_then( cx, FILTER_MAP_BOOL_THEN, @@ -62,7 +64,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", derefs = "*".repeat(needed_derefs) ), - Applicability::MachineApplicable, + applicability, ); } else { diag.help("consider using `filter` then `map` instead"); diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index 21f2ce8b7c9..bc96815944d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -100,7 +100,6 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: match x { UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())), UseKind::Borrowed(s) => { - #[expect(clippy::range_plus_one)] let range = s.map_range(cx, |_, src, range| { let src = src.get(range.clone())?; let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index f2dabdd3438..bcd54557331 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -3859,6 +3859,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where f is a function or closure that returns the `bool` type. + /// Also checks for equality comparisons like `option.map(f) == Some(true)` and `result.map(f) == Ok(true)`. /// /// ### Why is this bad? /// Readability. These can be written more concisely as `option.is_some_and(f)` and `result.is_ok_and(f)`. @@ -3869,6 +3870,11 @@ declare_clippy_lint! { /// # let result: Result<usize, ()> = Ok(1); /// option.map(|a| a > 10).unwrap_or_default(); /// result.map(|a| a > 10).unwrap_or_default(); + /// + /// option.map(|a| a > 10) == Some(true); + /// result.map(|a| a > 10) == Ok(true); + /// option.map(|a| a > 10) != Some(true); + /// result.map(|a| a > 10) != Ok(true); /// ``` /// Use instead: /// ```no_run @@ -3876,11 +3882,16 @@ declare_clippy_lint! { /// # let result: Result<usize, ()> = Ok(1); /// option.is_some_and(|a| a > 10); /// result.is_ok_and(|a| a > 10); + /// + /// option.is_some_and(|a| a > 10); + /// result.is_ok_and(|a| a > 10); + /// option.is_none_or(|a| a > 10); + /// !result.is_ok_and(|a| a > 10); /// ``` #[clippy::version = "1.77.0"] pub MANUAL_IS_VARIANT_AND, pedantic, - "using `.map(f).unwrap_or_default()`, which is more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`" + "using `.map(f).unwrap_or_default()` or `.map(f) == Some/Ok(true)`, which are more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`" } declare_clippy_lint! { @@ -5275,10 +5286,6 @@ impl Methods { } map_identity::check(cx, expr, recv, m_arg, name, span); manual_inspect::check(cx, expr, m_arg, name, span, self.msrv); - crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); - }, - (sym::map_break | sym::map_continue, [m_arg]) => { - crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); }, (sym::map_or, [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); @@ -5546,7 +5553,7 @@ impl Methods { // Handle method calls whose receiver and arguments may come from expansion if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind { match (path.ident.name, args) { - (sym::expect, [_]) if !matches!(method_call(recv), Some((sym::ok | sym::err, _, [], _, _))) => { + (sym::expect, [_]) => { unwrap_expect_used::check( cx, expr, diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index 6ce7dd3d4d0..04f0e3c0479 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -242,15 +242,23 @@ pub(super) fn check<'tcx>( let inner_arg = peel_blocks(arg); for_each_expr(cx, inner_arg, |ex| { let is_top_most_expr = ex.hir_id == inner_arg.hir_id; - if let hir::ExprKind::Call(fun, fun_args) = ex.kind { - let fun_span = if fun_args.is_empty() && is_top_most_expr { - Some(fun.span) - } else { - None - }; - if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) { - return ControlFlow::Break(()); - } + match ex.kind { + hir::ExprKind::Call(fun, fun_args) => { + let fun_span = if fun_args.is_empty() && is_top_most_expr { + Some(fun.span) + } else { + None + }; + if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) { + return ControlFlow::Break(()); + } + }, + hir::ExprKind::MethodCall(..) => { + if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, None) { + return ControlFlow::Break(()); + } + }, + _ => {}, } ControlFlow::Continue(()) }); diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 760ecf07589..18e2b384a46 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -7,9 +7,7 @@ use clippy_utils::{is_path_lang_item, sym}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{ - Block, Expr, ExprKind, Impl, Item, ItemKind, LangItem, Node, QPath, TyKind, VariantData, -}; +use rustc_hir::{Block, Expr, ExprKind, Impl, Item, ItemKind, LangItem, Node, QPath, TyKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index c4a3d10299b..5a5025973b5 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_attr_data_structures::{AttributeKind, find_attr}; -use rustc_hir as hir; -use rustc_hir::Attribute; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, Attribute}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocItemContainer; use rustc_session::declare_lint_pass; @@ -97,11 +97,23 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { } match it.kind { hir::ItemKind::Fn { .. } => { + if fn_is_externally_exported(cx, it.owner_id.to_def_id()) { + return; + } + let desc = "a function"; let attrs = cx.tcx.hir_attrs(it.hir_id()); check_missing_inline_attrs(cx, attrs, it.span, desc); }, - hir::ItemKind::Trait(ref _constness, ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => { + hir::ItemKind::Trait( + ref _constness, + ref _is_auto, + ref _unsafe, + _ident, + _generics, + _bounds, + trait_items, + ) => { // note: we need to check if the trait is exported so we can't use // `LateLintPass::check_trait_item` here. for &tit in trait_items { @@ -173,3 +185,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { check_missing_inline_attrs(cx, attrs, impl_item.span, desc); } } + +/// Checks if this function is externally exported, where #[inline] wouldn't have the desired effect +/// and a rustc warning would be triggered, see #15301 +fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool { + let attrs = cx.tcx.codegen_fn_attrs(def_id); + attrs.contains_extern_indicator() +} diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index fa61d0fa11a..399bf4e1806 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -66,7 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { }) = item.kind && let Some(trait_id) = trait_ref.trait_def_id() { - let trait_item_ids: DefIdSet = cx.tcx.associated_items(item.owner_id) + let trait_item_ids: DefIdSet = cx + .tcx + .associated_items(item.owner_id) .in_definition_order() .filter_map(|assoc_item| assoc_item.trait_item_def_id) .collect(); diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index d9f4fb271fb..a489c0a4a5a 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -171,14 +171,11 @@ impl<'tcx> Visitor<'tcx> for DivergenceVisitor<'_, 'tcx> { ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e), ExprKind::Call(func, _) => { let typ = self.cx.typeck_results().expr_ty(func); - match typ.kind() { - ty::FnDef(..) | ty::FnPtr(..) => { - let sig = typ.fn_sig(self.cx.tcx); - if self.cx.tcx.instantiate_bound_regions_with_erased(sig).output().kind() == &ty::Never { - self.report_diverging_sub_expr(e); - } - }, - _ => {}, + if typ.is_fn() { + let sig = typ.fn_sig(self.cx.tcx); + if self.cx.tcx.instantiate_bound_regions_with_erased(sig).output().kind() == &ty::Never { + self.report_diverging_sub_expr(e); + } } }, ExprKind::MethodCall(..) => { diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 2f1ab3d2652..31f51b45754 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -79,7 +79,7 @@ fn check_arguments<'tcx>( name: &str, fn_kind: &str, ) { - if let ty::FnDef(..) | ty::FnPtr(..) = type_definition.kind() { + if type_definition.is_fn() { let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in iter::zip(arguments, parameters) { if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind() diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 6a7c8436bad..a67545e419c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::has_iter_method; use clippy_utils::{is_trait_method, sym}; @@ -101,18 +101,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); - let body_value_sugg = snippet_with_applicability(cx, body.value.span, "..", &mut applicability); + let (body_value_sugg, is_macro_call) = + snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); let sugg = format!( "for {} in {} {}", body_param_sugg, for_each_rev_sugg, - match body.value.kind { - ExprKind::Block(block, _) if is_let_desugar(block) => { - format!("{{ {body_value_sugg} }}") - }, - ExprKind::Block(_, _) => body_value_sugg.to_string(), - _ => format!("{{ {body_value_sugg}; }}"), + if is_macro_call { + format!("{{ {body_value_sugg}; }}") + } else { + match body.value.kind { + ExprKind::Block(block, _) if is_let_desugar(block) => { + format!("{{ {body_value_sugg} }}") + }, + ExprKind::Block(_, _) => body_value_sugg.to_string(), + _ => format!("{{ {body_value_sugg}; }}"), + } } ); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index c97ecce75b4..7b057998063 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -246,8 +246,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - span.get_source_text(cx) - .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), + span.get_source_text(cx).map_or_else( + || "change the call to".to_owned(), + |src| format!("change `{src}` to"), + ), suggestion, Applicability::Unspecified, ); @@ -275,8 +277,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - span.get_source_text(cx) - .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), + span.get_source_text(cx).map_or_else( + || "change the call to".to_owned(), + |src| format!("change `{src}` to"), + ), suggestion, Applicability::Unspecified, ); @@ -308,9 +312,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { /// Functions marked with these attributes must have the exact signature. pub(crate) fn requires_exact_signature(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|&allow| attr.has_name(allow)) + attr.is_proc_macro_attr() }) } diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 3b86f1d1f59..b598a390005 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -65,11 +65,16 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { .. }) = item.kind { - for assoc_item in cx.tcx.associated_items(item.owner_id.def_id) + for assoc_item in cx + .tcx + .associated_items(item.owner_id.def_id) .filter_by_name_unhygienic(sym::new) { if let AssocKind::Fn { has_self: false, .. } = assoc_item.kind { - let impl_item = cx.tcx.hir_node_by_def_id(assoc_item.def_id.expect_local()).expect_impl_item(); + let impl_item = cx + .tcx + .hir_node_by_def_id(assoc_item.def_id.expect_local()) + .expect_impl_item(); if impl_item.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index a78a342d4fe..466beb04b07 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -3,12 +3,11 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary}; +use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary, sym}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; @@ -89,6 +88,18 @@ impl ArithmeticSideEffects { self.allowed_unary.contains(ty_string_elem) } + fn is_non_zero_u(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + if let ty::Adt(adt, substs) = ty.kind() + && cx.tcx.is_diagnostic_item(sym::NonZero, adt.did()) + && let int_type = substs.type_at(0) + && matches!(int_type.kind(), ty::Uint(_)) + { + true + } else { + false + } + } + /// Verifies built-in types that have specific allowed operations fn has_specific_allowed_type_and_operation<'tcx>( cx: &LateContext<'tcx>, @@ -97,33 +108,12 @@ impl ArithmeticSideEffects { rhs_ty: Ty<'tcx>, ) -> bool { let is_div_or_rem = matches!(op, hir::BinOpKind::Div | hir::BinOpKind::Rem); - let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| { - let tcx = cx.tcx; - - let ty::Adt(adt, substs) = ty.kind() else { return false }; - - if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { - return false; - } - - let int_type = substs.type_at(0); - let unsigned_int_types = [ - tcx.types.u8, - tcx.types.u16, - tcx.types.u32, - tcx.types.u64, - tcx.types.u128, - tcx.types.usize, - ]; - - unsigned_int_types.contains(&int_type) - }; let is_sat_or_wrap = |ty: Ty<'_>| { is_type_diagnostic_item(cx, ty, sym::Saturating) || is_type_diagnostic_item(cx, ty, sym::Wrapping) }; // If the RHS is `NonZero<u*>`, then division or module by zero will never occur. - if is_non_zero_u(cx, rhs_ty) && is_div_or_rem { + if Self::is_non_zero_u(cx, rhs_ty) && is_div_or_rem { return true; } @@ -219,6 +209,18 @@ impl ArithmeticSideEffects { let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); actual_lhs = expr_or_init(cx, actual_lhs); actual_rhs = expr_or_init(cx, actual_rhs); + + // `NonZeroU*.get() - 1`, will never overflow + if let hir::BinOpKind::Sub = op + && let hir::ExprKind::MethodCall(method, receiver, [], _) = actual_lhs.kind + && method.ident.name == sym::get + && let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs() + && Self::is_non_zero_u(cx, receiver_ty) + && let Some(1) = Self::literal_integer(cx, actual_rhs) + { + return; + } + let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs(); let rhs_ty = cx.typeck_results().expr_ty_adjusted(actual_rhs).peel_refs(); if self.has_allowed_binary(lhs_ty, rhs_ty) { @@ -227,6 +229,7 @@ impl ArithmeticSideEffects { if Self::has_specific_allowed_type_and_operation(cx, lhs_ty, op, rhs_ty) { return; } + let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) { if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op { // At least for integers, shifts are already handled by the CTFE diff --git a/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs index 821178a4315..55bb78cfce5 100644 --- a/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs +++ b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs @@ -2,11 +2,12 @@ use clippy_utils::consts::is_zero_integer_const; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; +use clippy_utils::ty::expr_type_is_certain; use rustc_ast::BinOpKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use super::MANUAL_IS_MULTIPLE_OF; @@ -22,9 +23,21 @@ pub(super) fn check<'tcx>( && let Some(operand) = uint_compare_to_zero(cx, op, lhs, rhs) && let ExprKind::Binary(operand_op, operand_left, operand_right) = operand.kind && operand_op.node == BinOpKind::Rem + && matches!( + cx.typeck_results().expr_ty_adjusted(operand_left).peel_refs().kind(), + ty::Uint(_) + ) + && matches!( + cx.typeck_results().expr_ty_adjusted(operand_right).peel_refs().kind(), + ty::Uint(_) + ) + && expr_type_is_certain(cx, operand_left) { let mut app = Applicability::MachineApplicable; - let divisor = Sugg::hir_with_applicability(cx, operand_right, "_", &mut app); + let divisor = deref_sugg( + Sugg::hir_with_applicability(cx, operand_right, "_", &mut app), + cx.typeck_results().expr_ty_adjusted(operand_right), + ); span_lint_and_sugg( cx, MANUAL_IS_MULTIPLE_OF, @@ -64,3 +77,11 @@ fn uint_compare_to_zero<'tcx>( matches!(cx.typeck_results().expr_ty_adjusted(operand).kind(), ty::Uint(_)).then_some(operand) } + +fn deref_sugg<'a>(sugg: Sugg<'a>, ty: Ty<'_>) -> Sugg<'a> { + if let ty::Ref(_, target_ty, _) = ty.kind() { + deref_sugg(sugg.deref(), *target_ty) + } else { + sugg + } +} diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 19d9acfc930..4197680dd04 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -96,6 +96,12 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Match(_, arms, _) = expr.kind { + // if the match is generated by an external macro, the writer does not control + // how the scrutinee (`match &scrutiny { ... }`) is matched + if expr.span.in_external_macro(cx.sess().source_map()) { + return; + } + for arm in arms { let pat = &arm.pat; if apply_lint(cx, pat, DerefPossible::Possible) { diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 94cdcf00054..b3058c51afd 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -584,7 +584,13 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ Some((Node::Stmt(_), _)) => (), Some((Node::LetStmt(l), _)) => { // Only trace simple bindings. e.g `let x = y;` - if let PatKind::Binding(BindingMode::NONE, id, _, None) = l.pat.kind { + if let PatKind::Binding(BindingMode::NONE, id, ident, None) = l.pat.kind + // Let's not lint for the current parameter. The user may still intend to mutate + // (or, if not mutate, then perhaps call a method that's not otherwise available + // for) the referenced value behind the parameter through this local let binding + // with the underscore being only temporary. + && !ident.name.as_str().starts_with('_') + { self.bindings.insert(id, args_idx); } else { set_skip_flag(); @@ -650,7 +656,14 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ .filter_map(|(i, arg)| { let param = &body.params[arg.idx]; match param.pat.kind { - PatKind::Binding(BindingMode::NONE, id, _, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => { + PatKind::Binding(BindingMode::NONE, id, ident, None) + if !is_lint_allowed(cx, PTR_ARG, param.hir_id) + // Let's not lint for the current parameter. The user may still intend to mutate + // (or, if not mutate, then perhaps call a method that's not otherwise available + // for) the referenced value behind the parameter with the underscore being only + // temporary. + && !ident.name.as_str().starts_with('_') => + { Some((id, i)) }, _ => { diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index d292ed86ea4..9281678b3d8 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -4,15 +4,20 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local}; +use clippy_utils::ty::implements_trait; +use clippy_utils::{ + expr_use_ctxt, fn_def_id, get_parent_expr, higher, is_in_const_context, is_integer_const, is_path_lang_item, + path_to_local, +}; +use rustc_ast::Mutability; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, LangItem, Node}; +use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::ty::{self, ClauseKind, GenericArgKind, PredicatePolarity, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::Span; use rustc_span::source_map::Spanned; +use rustc_span::{Span, sym}; use std::cmp::Ordering; declare_clippy_lint! { @@ -24,6 +29,12 @@ declare_clippy_lint! { /// The code is more readable with an inclusive range /// like `x..=y`. /// + /// ### Limitations + /// The lint is conservative and will trigger only when switching + /// from an exclusive to an inclusive range is provably safe from + /// a typing point of view. This corresponds to situations where + /// the range is used as an iterator, or for indexing. + /// /// ### Known problems /// Will add unnecessary pair of parentheses when the /// expression is not wrapped in a pair but starts with an opening parenthesis @@ -34,11 +45,6 @@ declare_clippy_lint! { /// exclusive ranges, because they essentially add an extra branch that /// LLVM may fail to hoist out of the loop. /// - /// This will cause a warning that cannot be fixed if the consumer of the - /// range only accepts a specific range type, instead of the generic - /// `RangeBounds` trait - /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). - /// /// ### Example /// ```no_run /// # let x = 0; @@ -71,11 +77,11 @@ declare_clippy_lint! { /// The code is more readable with an exclusive range /// like `x..y`. /// - /// ### Known problems - /// This will cause a warning that cannot be fixed if - /// the consumer of the range only accepts a specific range type, instead of - /// the generic `RangeBounds` trait - /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). + /// ### Limitations + /// The lint is conservative and will trigger only when switching + /// from an inclusive to an exclusive range is provably safe from + /// a typing point of view. This corresponds to situations where + /// the range is used as an iterator, or for indexing. /// /// ### Example /// ```no_run @@ -344,70 +350,188 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) -> None } -// exclusive range plus one: `x..(y+1)` -fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { - if expr.span.can_be_used_for_suggestions() - && let Some(higher::Range { - start, - end: Some(end), - limits: RangeLimits::HalfOpen, - }) = higher::Range::hir(expr) - && let Some(y) = y_plus_one(cx, end) +/// Check whether `expr` could switch range types without breaking the typing requirements. This is +/// generally the case when `expr` is used as an iterator for example, or as a slice or `&str` +/// index. +/// +/// FIXME: Note that the current implementation may still return false positives. A proper fix would +/// check that the obligations are still satisfied after switching the range type. +fn can_switch_ranges<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + original: RangeLimits, + inner_ty: Ty<'tcx>, +) -> bool { + let use_ctxt = expr_use_ctxt(cx, expr); + let (Node::Expr(parent_expr), false) = (use_ctxt.node, use_ctxt.is_ty_unified) else { + return false; + }; + + // Check if `expr` is the argument of a compiler-generated `IntoIter::into_iter(expr)` + if let ExprKind::Call(func, [arg]) = parent_expr.kind + && arg.hir_id == use_ctxt.child_id + && is_path_lang_item(cx, func, LangItem::IntoIterIntoIter) { - let span = expr.span; - span_lint_and_then( - cx, - RANGE_PLUS_ONE, - span, - "an inclusive range would be more readable", - |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_paren().to_string()); - let end = Sugg::hir(cx, y, "y").maybe_paren(); - match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) { - Some(true) => { - diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect); - }, - Some(false) => { - diag.span_suggestion( - span, - "use", - format!("{start}..={end}"), - Applicability::MachineApplicable, // snippet - ); - }, - None => {}, - } - }, - ); + return true; + } + + // Check if `expr` is used as the receiver of a method of the `Iterator`, `IntoIterator`, + // or `RangeBounds` traits. + if let ExprKind::MethodCall(_, receiver, _, _) = parent_expr.kind + && receiver.hir_id == use_ctxt.child_id + && let Some(method_did) = cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) + && let Some(trait_did) = cx.tcx.trait_of_item(method_did) + && matches!( + cx.tcx.get_diagnostic_name(trait_did), + Some(sym::Iterator | sym::IntoIterator | sym::RangeBounds) + ) + { + return true; + } + + // Check if `expr` is an argument of a call which requires an `Iterator`, `IntoIterator`, + // or `RangeBounds` trait. + if let ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) = parent_expr.kind + && let Some(id) = fn_def_id(cx, parent_expr) + && let Some(arg_idx) = args.iter().position(|e| e.hir_id == use_ctxt.child_id) + { + let input_idx = if matches!(parent_expr.kind, ExprKind::MethodCall(..)) { + arg_idx + 1 + } else { + arg_idx + }; + let inputs = cx + .tcx + .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).instantiate_identity()) + .inputs(); + let expr_ty = inputs[input_idx]; + // Check that the `expr` type is present only once, otherwise modifying just one of them might be + // risky if they are referenced using the same generic type for example. + if inputs.iter().enumerate().all(|(n, ty)| + n == input_idx + || !ty.walk().any(|arg| matches!(arg.kind(), + GenericArgKind::Type(ty) if ty == expr_ty))) + // Look for a clause requiring `Iterator`, `IntoIterator`, or `RangeBounds`, and resolving to `expr_type`. + && cx + .tcx + .param_env(id) + .caller_bounds() + .into_iter() + .any(|p| { + if let ClauseKind::Trait(t) = p.kind().skip_binder() + && t.polarity == PredicatePolarity::Positive + && matches!( + cx.tcx.get_diagnostic_name(t.trait_ref.def_id), + Some(sym::Iterator | sym::IntoIterator | sym::RangeBounds) + ) + { + t.self_ty() == expr_ty + } else { + false + } + }) + { + return true; + } + } + + // Check if `expr` is used for indexing, and if the switched range type could be used + // as well. + if let ExprKind::Index(outer_expr, index, _) = parent_expr.kind + && index.hir_id == expr.hir_id + // Build the switched range type (for example `RangeInclusive<usize>`). + && let Some(switched_range_def_id) = match original { + RangeLimits::HalfOpen => cx.tcx.lang_items().range_inclusive_struct(), + RangeLimits::Closed => cx.tcx.lang_items().range_struct(), + } + && let switched_range_ty = cx + .tcx + .type_of(switched_range_def_id) + .instantiate(cx.tcx, &[inner_ty.into()]) + // Check that the switched range type can be used for indexing the original expression + // through the `Index` or `IndexMut` trait. + && let ty::Ref(_, outer_ty, mutability) = cx.typeck_results().expr_ty_adjusted(outer_expr).kind() + && let Some(index_def_id) = match mutability { + Mutability::Not => cx.tcx.lang_items().index_trait(), + Mutability::Mut => cx.tcx.lang_items().index_mut_trait(), + } + && implements_trait(cx, *outer_ty, index_def_id, &[switched_range_ty.into()]) + // We could also check that the associated item of the `index_def_id` trait with the switched range type + // return the same type, but it is reasonable to expect so. We can't check that the result is identical + // in both `Index<Range<…>>` and `Index<RangeInclusive<…>>` anyway. + { + return true; } + + false +} + +// exclusive range plus one: `x..(y+1)` +fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + check_range_switch( + cx, + expr, + RangeLimits::HalfOpen, + y_plus_one, + RANGE_PLUS_ONE, + "an inclusive range would be more readable", + "..=", + ); } // inclusive range minus one: `x..=(y-1)` -fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { +fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + check_range_switch( + cx, + expr, + RangeLimits::Closed, + y_minus_one, + RANGE_MINUS_ONE, + "an exclusive range would be more readable", + "..", + ); +} + +/// Check for a `kind` of range in `expr`, check for `predicate` on the end, +/// and emit the `lint` with `msg` and the `operator`. +fn check_range_switch<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + kind: RangeLimits, + predicate: impl for<'hir> FnOnce(&LateContext<'_>, &Expr<'hir>) -> Option<&'hir Expr<'hir>>, + lint: &'static Lint, + msg: &'static str, + operator: &str, +) { if expr.span.can_be_used_for_suggestions() && let Some(higher::Range { start, end: Some(end), - limits: RangeLimits::Closed, + limits, }) = higher::Range::hir(expr) - && let Some(y) = y_minus_one(cx, end) + && limits == kind + && let Some(y) = predicate(cx, end) + && can_switch_ranges(cx, expr, kind, cx.typeck_results().expr_ty(y)) { - span_lint_and_then( - cx, - RANGE_MINUS_ONE, - expr.span, - "an exclusive range would be more readable", - |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_paren().to_string()); - let end = Sugg::hir(cx, y, "y").maybe_paren(); - diag.span_suggestion( - expr.span, - "use", - format!("{start}..{end}"), - Applicability::MachineApplicable, // snippet - ); - }, - ); + let span = expr.span; + span_lint_and_then(cx, lint, span, msg, |diag| { + let mut app = Applicability::MachineApplicable; + let start = start.map_or(String::new(), |x| { + Sugg::hir_with_applicability(cx, x, "<x>", &mut app) + .maybe_paren() + .to_string() + }); + let end = Sugg::hir_with_applicability(cx, y, "<y>", &mut app).maybe_paren(); + match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) { + Some(true) => { + diag.span_suggestion(span, "use", format!("({start}{operator}{end})"), app); + }, + Some(false) => { + diag.span_suggestion(span, "use", format!("{start}{operator}{end}"), app); + }, + None => {}, + } + }); } } @@ -494,7 +618,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { } } -fn y_plus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> { +fn y_plus_one<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { match expr.kind { ExprKind::Binary( Spanned { @@ -515,7 +639,7 @@ fn y_plus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<' } } -fn y_minus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> { +fn y_minus_one<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { match expr.kind { ExprKind::Binary( Spanned { diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 85fde780e68..67eb71f7d07 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{AssocKind, AssocItem}; +use rustc_middle::ty::{AssocItem, AssocKind}; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -53,11 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { for id in cx.tcx.hir_free_items() { if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. }) && let item = cx.tcx.hir_item(id) - && let ItemKind::Impl(Impl { - of_trait, - self_ty, - .. - }) = &item.kind + && let ItemKind::Impl(Impl { of_trait, self_ty, .. }) = &item.kind && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind { if !map.contains_key(res) { @@ -127,7 +123,9 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { }, None => { for assoc_item in cx.tcx.associated_items(id.owner_id).in_definition_order() { - let AssocKind::Fn { name, .. } = assoc_item.kind else { continue }; + let AssocKind::Fn { name, .. } = assoc_item.kind else { + continue; + }; let impl_span = cx.tcx.def_span(assoc_item.def_id); let hir_id = cx.tcx.local_def_id_to_hir_id(assoc_item.def_id.expect_local()); if let Some(trait_spans) = existing_name.trait_methods.get(&name) { @@ -140,10 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { |diag| { // TODO should we `span_note` on every trait? // iterate on trait_spans? - diag.span_note( - trait_spans[0], - format!("existing `{name}` defined here"), - ); + diag.span_note(trait_spans[0], format!("existing `{name}` defined here")); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index e67afc7f5a8..5a3e4b7adf6 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -1,8 +1,12 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; +use clippy_utils::usage::is_todo_unimplemented_stub; use rustc_hir::def::DefKind; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; -use rustc_hir::{Body, Defaultness, Expr, ExprKind, FnDecl, HirId, Node, TraitItem, YieldSource}; +use rustc_hir::{ + Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Defaultness, Expr, ExprKind, FnDecl, HirId, Node, + TraitItem, YieldSource, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; @@ -81,11 +85,8 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { let is_async_block = matches!( ex.kind, - ExprKind::Closure(rustc_hir::Closure { - kind: rustc_hir::ClosureKind::Coroutine(rustc_hir::CoroutineKind::Desugared( - rustc_hir::CoroutineDesugaring::Async, - _ - )), + ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)), .. }) ); @@ -120,6 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { && fn_kind.asyncness().is_async() && !is_def_id_trait_method(cx, def_id) && !is_default_trait_impl(cx, def_id) + && !async_fn_contains_todo_unimplemented_macro(cx, body) { let mut visitor = AsyncFnVisitor { cx, @@ -203,3 +205,18 @@ fn is_default_trait_impl(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { }) ) } + +fn async_fn_contains_todo_unimplemented_macro(cx: &LateContext<'_>, body: &Body<'_>) -> bool { + if let ExprKind::Closure(closure) = body.value.kind + && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = closure.kind + && let body = cx.tcx.hir_body(closure.body) + && let ExprKind::Block(block, _) = body.value.kind + && block.stmts.is_empty() + && let Some(expr) = block.expr + && let ExprKind::DropTemps(inner) = expr.kind + { + return is_todo_unimplemented_stub(cx, inner); + } + + false +} diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 12da891a71b..dff39974a37 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -1,12 +1,10 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::sym; +use clippy_utils::usage::is_todo_unimplemented_stub; use clippy_utils::visitors::is_local_used; -use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; +use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -60,18 +58,6 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; let parent_item = cx.tcx.hir_expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.owner_id); - let contains_todo = |cx, body: &'_ Body<'_>| -> bool { - clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { - if let Some(macro_call) = root_macro_call_first_node(cx, e) - && cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - }) - .is_some() - }; if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind && assoc_item.is_method() && let ImplItemKind::Fn(.., body_id) = &impl_item.kind @@ -79,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { && let body = cx.tcx.hir_body(*body_id) && let [self_param, ..] = body.params && !is_local_used(cx, body, self_param.pat.hir_id) - && !contains_todo(cx, body) + && !is_todo_unimplemented_stub(cx, body.value) { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs index b7a1d5b2123..12f2804dbaa 100644 --- a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs +++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs @@ -6,7 +6,7 @@ use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, UseKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext as _}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; @@ -59,7 +59,7 @@ impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]); impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if !item.span.in_external_macro(cx.sess().source_map()) + if !item.span.from_expansion() && let ItemKind::Use(path, UseKind::Single(ident)) = item.kind // Ignore imports that already use Underscore && ident.name != kw::Underscore diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 380ddea4e1e..e5b20c0e0a1 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -176,6 +176,33 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } }, + ExprKind::MethodCall(path, recv, [arg], _) => { + if matches!( + path.ident.name, + sym::map | sym::map_err | sym::map_break | sym::map_continue + ) && has_eligible_receiver(cx, recv, e) + && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From)) + && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind() + && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice() + && same_type_and_consts(from_ty, to_ty) + { + span_lint_and_then( + cx, + USELESS_CONVERSION, + e.span.with_lo(recv.span.hi()), + format!("useless conversion to the same type: `{from_ty}`"), + |diag| { + diag.suggest_remove_item( + cx, + e.span.with_lo(recv.span.hi()), + "consider removing", + Applicability::MachineApplicable, + ); + }, + ); + } + }, + ExprKind::MethodCall(name, recv, [], _) => { if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into { let a = cx.typeck_results().expr_ty(e); @@ -412,32 +439,6 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } -/// Check if `arg` is a `Into::into` or `From::from` applied to `receiver` to give `expr`, through a -/// higher-order mapping function. -pub fn check_function_application(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { - if has_eligible_receiver(cx, recv, expr) - && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From)) - && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind() - && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice() - && same_type_and_consts(from_ty, to_ty) - { - span_lint_and_then( - cx, - USELESS_CONVERSION, - expr.span.with_lo(recv.span.hi()), - format!("useless conversion to the same type: `{from_ty}`"), - |diag| { - diag.suggest_remove_item( - cx, - expr.span.with_lo(recv.span.hi()), - "consider removing", - Applicability::MachineApplicable, - ); - }, - ); - } -} - fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) -> bool { if is_inherent_method_call(cx, expr) { matches!( diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs index 88b099c477f..41fafc08c25 100644 --- a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs +++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::paths; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::{AttrStyle, DelimArgs}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::{ @@ -11,7 +12,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_lint_defs::declare_tool_lint; use rustc_middle::ty::TyCtxt; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_tool_lint! { /// ### What it does @@ -88,7 +88,10 @@ impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown { } // Is it derived? - if !find_attr!(cx.tcx.get_all_attrs(item.owner_id), AttributeKind::AutomaticallyDerived(..)) { + if !find_attr!( + cx.tcx.get_all_attrs(item.owner_id), + AttributeKind::AutomaticallyDerived(..) + ) { return; } diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs index 45a866030b2..fda65bc84ed 100644 --- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -1,7 +1,7 @@ use crate::internal_paths; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::is_lint_allowed; use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::{is_lint_allowed, sym}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; @@ -12,9 +12,9 @@ use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; declare_tool_lint! { /// ### What it does @@ -160,9 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { let body = cx.tcx.hir_body_owned_by( impl_item_refs .iter() - .find(|iiref| iiref.ident.as_str() == "lint_vec") + .find(|&&iiref| cx.tcx.item_name(iiref.owner_id) == sym::lint_vec) .expect("LintPass needs to implement lint_vec") - .id .owner_id .def_id, ); diff --git a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs index 70b3c03d2bb..66aeb910891 100644 --- a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs +++ b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs @@ -1,6 +1,7 @@ use crate::internal_paths; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -40,7 +41,9 @@ impl LateLintPass<'_> for MsrvAttrImpl { .filter(|t| matches!(t.kind(), GenericArgKind::Type(_))) .any(|t| internal_paths::MSRV_STACK.matches_ty(cx, t.expect_ty())) }) - && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes") + && !items + .iter() + .any(|&item| cx.tcx.item_name(item.owner_id) == sym::check_attributes) { let span = cx.sess().source_map().span_through_char(item.span, '{'); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 645b644d9f4..19e71f6af1d 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: <!-- begin autogenerated nightly --> ``` -nightly-2025-07-10 +nightly-2025-07-25 ``` <!-- end autogenerated nightly --> diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 8453165818b..625e1eead21 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -22,10 +22,13 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { { diag.help(format!( "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", - &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { - // extract just major + minor version and ignore patch versions - format!("rust-{}", n.rsplit_once('.').unwrap().1) - }) + &option_env!("RUST_RELEASE_NUM").map_or_else( + || "master".to_string(), + |n| { + // extract just major + minor version and ignore patch versions + format!("rust-{}", n.rsplit_once('.').unwrap().1) + } + ) )); } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ff1ee663f9b..ce5af4d2f48 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -89,8 +89,8 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; -use rustc_ast::join_path_syms; use rustc_ast::ast::{self, LitKind, RangeLimits}; +use rustc_ast::join_path_syms; use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; @@ -114,7 +114,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::hir::place::PlaceBase; use rustc_middle::lint::LevelAndSource; use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, PointerCoercion}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, @@ -1897,6 +1897,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// * `|x| { return x }` /// * `|x| { return x; }` /// * `|(x, y)| (x, y)` +/// * `|[x, y]| [x, y]` /// /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead. fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { @@ -1907,9 +1908,9 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { .get(pat.hir_id) .is_some_and(|mode| matches!(mode.0, ByRef::Yes(_))) { - // If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics, - // the inner patterns become references. Don't consider this the identity function - // as that changes types. + // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then + // due to match ergonomics, the inner patterns become references. Don't consider this + // the identity function as that changes types. return false; } @@ -1922,6 +1923,13 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { { pats.iter().zip(tup).all(|(pat, expr)| check_pat(cx, pat, expr)) }, + (PatKind::Slice(before, slice, after), ExprKind::Array(arr)) + if slice.is_none() && before.len() + after.len() == arr.len() => + { + (before.iter().chain(after)) + .zip(arr) + .all(|(pat, expr)| check_pat(cx, pat, expr)) + }, _ => false, } } @@ -3269,15 +3277,13 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St if go_up_by > max_super { // `super` chain would be too long, just use the absolute path instead - join_path_syms( - once(kw::Crate).chain(to.data.iter().filter_map(|el| { - if let DefPathData::TypeNs(sym) = el.data { - Some(sym) - } else { - None - } - })) - ) + join_path_syms(once(kw::Crate).chain(to.data.iter().filter_map(|el| { + if let DefPathData::TypeNs(sym) = el.data { + Some(sym) + } else { + None + } + }))) } else { join_path_syms(repeat_n(kw::Super, go_up_by).chain(path)) } @@ -3560,3 +3566,14 @@ pub fn potential_return_of_enclosing_body(cx: &LateContext<'_>, expr: &Expr<'_>) // enclosing body. false } + +/// Checks if the expression has adjustments that require coercion, for example: dereferencing with +/// overloaded deref, coercing pointers and `dyn` objects. +pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + cx.typeck_results().expr_adjustments(expr).iter().any(|adj| { + matches!( + adj.kind, + Adjust::Deref(Some(_)) | Adjust::Pointer(PointerCoercion::Unsize) | Adjust::NeverToAny + ) + }) +} diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index c681806517a..ea8cfc59356 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -308,10 +308,11 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n None } }), - ItemKind::Impl(..) | ItemKind::Trait(..) - => tcx.associated_items(local_id).filter_by_name_unhygienic(name) - .find(|assoc_item| ns.matches(Some(assoc_item.namespace()))) - .map(|assoc_item| assoc_item.def_id), + ItemKind::Impl(..) | ItemKind::Trait(..) => tcx + .associated_items(local_id) + .filter_by_name_unhygienic(name) + .find(|assoc_item| ns.matches(Some(assoc_item.namespace()))) + .map(|assoc_item| assoc_item.def_id), _ => None, } } diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 8a8218c6976..934be97d94e 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -98,6 +98,7 @@ generate! { ceil_char_boundary, chain, chars, + check_attributes, checked_abs, checked_add, checked_isqrt, @@ -196,6 +197,7 @@ generate! { kw, last, lazy_static, + lint_vec, ln, lock, lock_api, @@ -261,6 +263,7 @@ generate! { read_to_end, read_to_string, read_unaligned, + redundant_imports, redundant_pub_crate, regex, rem_euclid, diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index fe208c032f4..d70232ef3aa 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -492,10 +492,7 @@ pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { /// Returns `true` if the given type is an `unsafe` function. pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::FnDef(..) | ty::FnPtr(..) => ty.fn_sig(cx.tcx).safety().is_unsafe(), - _ => false, - } + ty.is_fn() && ty.fn_sig(cx.tcx).safety().is_unsafe() } /// Returns the base type for HIR references and pointers. diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 84df36c75bf..d9c7e6eac9f 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -12,10 +12,11 @@ //! be considered a bug. use crate::paths::{PathNS, lookup_path}; +use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty}; -use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind}; +use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, Param, PathSegment, QPath, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty}; use rustc_span::Span; @@ -24,22 +25,24 @@ mod certainty; use certainty::{Certainty, Meet, join, meet}; pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - expr_type_certainty(cx, expr).is_certain() + expr_type_certainty(cx, expr, false).is_certain() } -fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { +/// Determine the type certainty of `expr`. `in_arg` indicates that the expression happens within +/// the evaluation of a function or method call argument. +fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>, in_arg: bool) -> Certainty { let certainty = match &expr.kind { ExprKind::Unary(_, expr) | ExprKind::Field(expr, _) | ExprKind::Index(expr, _, _) - | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr), + | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr, in_arg), - ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))), + ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))), ExprKind::Call(callee, args) => { - let lhs = expr_type_certainty(cx, callee); + let lhs = expr_type_certainty(cx, callee, false); let rhs = if type_is_inferable_from_arguments(cx, expr) { - meet(args.iter().map(|arg| expr_type_certainty(cx, arg))) + meet(args.iter().map(|arg| expr_type_certainty(cx, arg, true))) } else { Certainty::Uncertain }; @@ -47,7 +50,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { }, ExprKind::MethodCall(method, receiver, args, _) => { - let mut receiver_type_certainty = expr_type_certainty(cx, receiver); + let mut receiver_type_certainty = expr_type_certainty(cx, receiver, false); // Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method // identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`, // for example. So update the `DefId` in `receiver_type_certainty` (if any). @@ -59,7 +62,8 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false); let rhs = if type_is_inferable_from_arguments(cx, expr) { meet( - std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))), + std::iter::once(receiver_type_certainty) + .chain(args.iter().map(|arg| expr_type_certainty(cx, arg, true))), ) } else { Certainty::Uncertain @@ -67,16 +71,39 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { lhs.join(rhs) }, - ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))), + ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))), - ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)), + ExprKind::Binary(_, lhs, rhs) => { + // If one of the side of the expression is uncertain, the certainty will come from the other side, + // with no information on the type. + match ( + expr_type_certainty(cx, lhs, in_arg), + expr_type_certainty(cx, rhs, in_arg), + ) { + (Certainty::Uncertain, Certainty::Certain(_)) | (Certainty::Certain(_), Certainty::Uncertain) => { + Certainty::Certain(None) + }, + (l, r) => l.meet(r), + } + }, - ExprKind::Lit(_) => Certainty::Certain(None), + ExprKind::Lit(lit) => { + if !in_arg + && matches!( + lit.node, + LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) + ) + { + Certainty::Uncertain + } else { + Certainty::Certain(None) + } + }, ExprKind::Cast(_, ty) => type_certainty(cx, ty), ExprKind::If(_, if_expr, Some(else_expr)) => { - expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr)) + expr_type_certainty(cx, if_expr, in_arg).join(expr_type_certainty(cx, else_expr, in_arg)) }, ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false), @@ -188,6 +215,20 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo certainty } +/// Tries to tell whether `param` resolves to something certain, e.g., a non-wildcard type if +/// present. The certainty `DefId` is cleared before returning. +fn param_certainty(cx: &LateContext<'_>, param: &Param<'_>) -> Certainty { + let owner_did = cx.tcx.hir_enclosing_body_owner(param.hir_id); + let Some(fn_decl) = cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.local_def_id_to_hir_id(owner_did)) else { + return Certainty::Uncertain; + }; + let inputs = fn_decl.inputs; + let body_params = cx.tcx.hir_body_owned_by(owner_did).params; + std::iter::zip(body_params, inputs) + .find(|(p, _)| p.hir_id == param.hir_id) + .map_or(Certainty::Uncertain, |(_, ty)| type_certainty(cx, ty).clear_def_id()) +} + fn path_segment_certainty( cx: &LateContext<'_>, parent_certainty: Certainty, @@ -240,15 +281,16 @@ fn path_segment_certainty( // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`. Res::Local(hir_id) => match cx.tcx.parent_hir_node(hir_id) { - // An argument's type is always certain. - Node::Param(..) => Certainty::Certain(None), + // A parameter's type is not always certain, as it may come from an untyped closure definition, + // or from a wildcard in a typed closure definition. + Node::Param(param) => param_certainty(cx, param), // A local's type is certain if its type annotation is certain or it has an initializer whose // type is certain. Node::LetStmt(local) => { let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty)); let rhs = local .init - .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init)); + .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init, false)); let certainty = lhs.join(rhs); if resolves_to_type { certainty diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 1b049b6d12c..76d43feee12 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -1,3 +1,4 @@ +use crate::macros::root_macro_call_first_node; use crate::visitors::{Descend, Visitable, for_each_expr, for_each_expr_without_closures}; use crate::{self as utils, get_enclosing_loop_or_multi_call_closure}; use core::ops::ControlFlow; @@ -9,6 +10,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; +use rustc_span::sym; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> { @@ -140,6 +142,46 @@ impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> { } } +/// Checks if the given expression is a macro call to `todo!()` or `unimplemented!()`. +pub fn is_todo_unimplemented_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + root_macro_call_first_node(cx, expr).is_some_and(|macro_call| { + [sym::todo_macro, sym::unimplemented_macro] + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, macro_call.def_id)) + }) +} + +/// Checks if the given expression is a stub, i.e., a `todo!()` or `unimplemented!()` expression, +/// or a block whose last expression is a `todo!()` or `unimplemented!()`. +pub fn is_todo_unimplemented_stub(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let ExprKind::Block(block, _) = expr.kind { + if let Some(last_expr) = block.expr { + return is_todo_unimplemented_macro(cx, last_expr); + } + + return block.stmts.last().is_some_and(|stmt| { + if let hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) = stmt.kind { + return is_todo_unimplemented_macro(cx, expr); + } + false + }); + } + + is_todo_unimplemented_macro(cx, expr) +} + +/// Checks if the given expression contains macro call to `todo!()` or `unimplemented!()`. +pub fn contains_todo_unimplement_macro(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { + for_each_expr_without_closures(expr, |e| { + if is_todo_unimplemented_macro(cx, e) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} + pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { for_each_expr_without_closures(expression, |e| { match e.kind { diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index f46e079db3f..0edb80edd04 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-07-10" +channel = "nightly-2025-07-25" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs index b45edf23455..194ed84d04c 100644 --- a/src/tools/clippy/rustc_tools_util/src/lib.rs +++ b/src/tools/clippy/rustc_tools_util/src/lib.rs @@ -157,7 +157,8 @@ pub fn get_commit_date() -> Option<String> { #[must_use] pub fn get_compiler_version() -> Option<String> { - get_output("rustc", &["-V"]) + let compiler = std::option_env!("RUSTC").unwrap_or("rustc"); + get_output(compiler, &["-V"]) } #[must_use] @@ -172,6 +173,8 @@ pub fn get_channel(compiler_version: Option<String>) -> String { return String::from("beta"); } else if rustc_output.contains("nightly") { return String::from("nightly"); + } else if rustc_output.contains("dev") { + return String::from("dev"); } } diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 83f91ccaa7b..464efc45c6b 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -162,6 +162,10 @@ impl TestContext { // however has some staging logic that is hurting us here, so to work around // that we set both the "real" and "staging" rustc to TEST_RUSTC, including the // associated library paths. + #[expect( + clippy::option_env_unwrap, + reason = "TEST_RUSTC will ensure that the requested env vars are set during compile time" + )] if let Some(rustc) = option_env!("TEST_RUSTC") { let libdir = option_env!("TEST_RUSTC_LIB").unwrap(); let sysroot = option_env!("TEST_SYSROOT").unwrap(); @@ -169,10 +173,7 @@ impl TestContext { p.envs.push(("RUSTC_REAL_LIBDIR".into(), Some(libdir.into()))); p.envs.push(("RUSTC_SNAPSHOT".into(), Some(rustc.into()))); p.envs.push(("RUSTC_SNAPSHOT_LIBDIR".into(), Some(libdir.into()))); - p.envs.push(( - "RUSTC_SYSROOT".into(), - Some(sysroot.into()), - )); + p.envs.push(("RUSTC_SYSROOT".into(), Some(sysroot.into()))); } p }, diff --git a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr index 8a85d38fba3..608264beb10 100644 --- a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr +++ b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr @@ -18,6 +18,8 @@ error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is | LL | sleep(Duration::new(1, 0)); | ^^^^^ + | + = note: you may want to conditionally increase the MSRV considered by Clippy using the `clippy::msrv` attribute error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr b/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr index 020b3cc7878..a5dfd7015a3 100644 --- a/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr +++ b/src/tools/clippy/tests/ui-toml/enum_variant_size/enum_variant_size.stderr @@ -12,7 +12,7 @@ LL | | } | = note: `-D clippy::large-enum-variant` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]` -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B([u8; 501]), LL + B(Box<[u8; 501]>), diff --git a/src/tools/clippy/tests/ui/approx_const.rs b/src/tools/clippy/tests/ui/approx_const.rs index 6461666be8f..fc493421a16 100644 --- a/src/tools/clippy/tests/ui/approx_const.rs +++ b/src/tools/clippy/tests/ui/approx_const.rs @@ -106,4 +106,19 @@ fn main() { //~^ approx_constant let no_tau = 6.3; + + // issue #15194 + #[allow(clippy::excessive_precision)] + let x: f64 = 3.1415926535897932384626433832; + //~^ approx_constant + + #[allow(clippy::excessive_precision)] + let _: f64 = 003.14159265358979311599796346854418516159057617187500; + //~^ approx_constant + + let almost_frac_1_sqrt_2 = 00.70711; + //~^ approx_constant + + let almost_frac_1_sqrt_2 = 00.707_11; + //~^ approx_constant } diff --git a/src/tools/clippy/tests/ui/approx_const.stderr b/src/tools/clippy/tests/ui/approx_const.stderr index f7bda0468cb..32a3517ff2e 100644 --- a/src/tools/clippy/tests/ui/approx_const.stderr +++ b/src/tools/clippy/tests/ui/approx_const.stderr @@ -184,5 +184,37 @@ LL | let almost_tau = 6.28; | = help: consider using the constant directly -error: aborting due to 23 previous errors +error: approximate value of `f{32, 64}::consts::PI` found + --> tests/ui/approx_const.rs:112:18 + | +LL | let x: f64 = 3.1415926535897932384626433832; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly + +error: approximate value of `f{32, 64}::consts::PI` found + --> tests/ui/approx_const.rs:116:18 + | +LL | let _: f64 = 003.14159265358979311599796346854418516159057617187500; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly + +error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found + --> tests/ui/approx_const.rs:119:32 + | +LL | let almost_frac_1_sqrt_2 = 00.70711; + | ^^^^^^^^ + | + = help: consider using the constant directly + +error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found + --> tests/ui/approx_const.rs:122:32 + | +LL | let almost_frac_1_sqrt_2 = 00.707_11; + | ^^^^^^^^^ + | + = help: consider using the constant directly + +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr index 5556b0df88c..ce726206b0c 100644 --- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr +++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr @@ -5,7 +5,7 @@ LL | let _ = Arc::new(RefCell::new(42)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `Arc<RefCell<i32>>` is not `Send` and `Sync` as `RefCell<i32>` is not `Sync` - = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: if the `Arc` will not be used across threads replace it with an `Rc` = help: otherwise make `RefCell<i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex` = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]` @@ -17,7 +17,7 @@ LL | let _ = Arc::new(mutex.lock().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `Arc<MutexGuard<'_, i32>>` is not `Send` and `Sync` as `MutexGuard<'_, i32>` is not `Send` - = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: if the `Arc` will not be used across threads replace it with an `Rc` = help: otherwise make `MutexGuard<'_, i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex` error: usage of an `Arc` that is not `Send` and `Sync` @@ -27,7 +27,7 @@ LL | let _ = Arc::new(&42 as *const i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `Arc<*const i32>` is not `Send` and `Sync` as `*const i32` is neither `Send` nor `Sync` - = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: if the `Arc` will not be used across threads replace it with an `Rc` = help: otherwise make `*const i32` `Send` and `Sync` or consider a wrapper type such as `Mutex` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index 21be2af201f..3245b2c983e 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -664,6 +664,20 @@ pub fn issue_12318() { //~^ arithmetic_side_effects } +pub fn issue_15225() { + use core::num::{NonZero, NonZeroU8}; + + let one = const { NonZeroU8::new(1).unwrap() }; + let _ = one.get() - 1; + + let one: NonZero<u8> = const { NonZero::new(1).unwrap() }; + let _ = one.get() - 1; + + type AliasedType = u8; + let one: NonZero<AliasedType> = const { NonZero::new(1).unwrap() }; + let _ = one.get() - 1; +} + pub fn explicit_methods() { use core::ops::Add; let one: i32 = 1; diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index e15fb612be5..4150493ba94 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -758,13 +758,13 @@ LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:670:5 + --> tests/ui/arithmetic_side_effects.rs:684:5 | LL | one.add(&one); | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:672:5 + --> tests/ui/arithmetic_side_effects.rs:686:5 | LL | Box::new(one).add(one); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index eee61f949e7..3754b9dfe74 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -84,6 +84,7 @@ mod issue14871 { const ONE: Self; } + #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet) pub const trait NumberConstants { fn constant(value: usize) -> Self; } diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs index 13ffcee0a3c..0b878d4f490 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -84,6 +84,7 @@ mod issue14871 { const ONE: Self; } + #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet) pub const trait NumberConstants { fn constant(value: usize) -> Self; } diff --git a/src/tools/clippy/tests/ui/auxiliary/external_item.rs b/src/tools/clippy/tests/ui/auxiliary/external_item.rs index ca4bc369e44..621e18f5c01 100644 --- a/src/tools/clippy/tests/ui/auxiliary/external_item.rs +++ b/src/tools/clippy/tests/ui/auxiliary/external_item.rs @@ -4,4 +4,4 @@ impl _ExternalStruct { pub fn _foo(self) {} } -pub fn _exernal_foo() {} +pub fn _external_foo() {} diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed index 279a5b6e1ff..6175275ef04 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.fixed +++ b/src/tools/clippy/tests/ui/checked_conversions.fixed @@ -95,7 +95,7 @@ pub const fn issue_8898(i: u32) -> bool { #[clippy::msrv = "1.33"] fn msrv_1_33() { let value: i64 = 33; - let _ = value <= (u32::MAX as i64) && value >= 0; + let _ = value <= (u32::max_value() as i64) && value >= 0; } #[clippy::msrv = "1.34"] diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs index c339bc674bb..9ed0e8f660d 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.rs +++ b/src/tools/clippy/tests/ui/checked_conversions.rs @@ -95,13 +95,13 @@ pub const fn issue_8898(i: u32) -> bool { #[clippy::msrv = "1.33"] fn msrv_1_33() { let value: i64 = 33; - let _ = value <= (u32::MAX as i64) && value >= 0; + let _ = value <= (u32::max_value() as i64) && value >= 0; } #[clippy::msrv = "1.34"] fn msrv_1_34() { let value: i64 = 34; - let _ = value <= (u32::MAX as i64) && value >= 0; + let _ = value <= (u32::max_value() as i64) && value >= 0; //~^ checked_conversions } diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr index 3841b9d5a4d..624876dacb2 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.stderr +++ b/src/tools/clippy/tests/ui/checked_conversions.stderr @@ -100,8 +100,8 @@ LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; error: checked cast can be simplified --> tests/ui/checked_conversions.rs:104:13 | -LL | let _ = value <= (u32::MAX as i64) && value >= 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` +LL | let _ = value <= (u32::max_value() as i64) && value >= 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/expect.rs b/src/tools/clippy/tests/ui/expect.rs index 8f7379f0021..1ab01ecfcfe 100644 --- a/src/tools/clippy/tests/ui/expect.rs +++ b/src/tools/clippy/tests/ui/expect.rs @@ -16,7 +16,26 @@ fn expect_result() { //~^ expect_used } +#[allow(clippy::ok_expect)] +#[allow(clippy::err_expect)] +fn issue_15247() { + let x: Result<u8, u8> = Err(0); + x.ok().expect("Huh"); + //~^ expect_used + + { x.ok() }.expect("..."); + //~^ expect_used + + let y: Result<u8, u8> = Ok(0); + y.err().expect("Huh"); + //~^ expect_used + + { y.err() }.expect("..."); + //~^ expect_used +} + fn main() { expect_option(); expect_result(); + issue_15247(); } diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr index 70cf3072003..353fb776531 100644 --- a/src/tools/clippy/tests/ui/expect.stderr +++ b/src/tools/clippy/tests/ui/expect.stderr @@ -24,5 +24,37 @@ LL | let _ = res.expect_err(""); | = note: if this value is an `Ok`, it will panic -error: aborting due to 3 previous errors +error: used `expect()` on an `Option` value + --> tests/ui/expect.rs:23:5 + | +LL | x.ok().expect("Huh"); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: used `expect()` on an `Option` value + --> tests/ui/expect.rs:26:5 + | +LL | { x.ok() }.expect("..."); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: used `expect()` on an `Option` value + --> tests/ui/expect.rs:30:5 + | +LL | y.err().expect("Huh"); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: used `expect()` on an `Option` value + --> tests/ui/expect.rs:33:5 + | +LL | { y.err() }.expect("..."); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed index 73eaebf773c..b923521afde 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.fixed +++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed @@ -90,17 +90,30 @@ fn main() { "foo" } - Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + const fn const_evaluable() -> &'static str { + "foo" + } + + Some("foo").unwrap_or_else(|| panic!("{}", get_string())); //~^ expect_fun_call - Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + Some("foo").unwrap_or_else(|| panic!("{}", get_string())); //~^ expect_fun_call - Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + Some("foo").unwrap_or_else(|| panic!("{}", get_string())); //~^ expect_fun_call - Some("foo").unwrap_or_else(|| { panic!("{}", get_static_str()) }); + Some("foo").unwrap_or_else(|| panic!("{}", get_static_str())); //~^ expect_fun_call - Some("foo").unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) }); + Some("foo").unwrap_or_else(|| panic!("{}", get_non_static_str(&0))); + //~^ expect_fun_call + + Some("foo").unwrap_or_else(|| panic!("{}", const_evaluable())); //~^ expect_fun_call + + const { + Some("foo").expect(const_evaluable()); + } + + Some("foo").expect(const { const_evaluable() }); } //Issue #3839 @@ -122,4 +135,15 @@ fn main() { let format_capture_and_value: Option<i32> = None; format_capture_and_value.unwrap_or_else(|| panic!("{error_code}, {}", 1)); //~^ expect_fun_call + + // Issue #15056 + let a = false; + Some(5).expect(if a { "a" } else { "b" }); + + let return_in_expect: Option<i32> = None; + return_in_expect.expect(if true { + "Error" + } else { + return; + }); } diff --git a/src/tools/clippy/tests/ui/expect_fun_call.rs b/src/tools/clippy/tests/ui/expect_fun_call.rs index ecebc9ebfb6..bc58d24bc81 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.rs +++ b/src/tools/clippy/tests/ui/expect_fun_call.rs @@ -90,6 +90,10 @@ fn main() { "foo" } + const fn const_evaluable() -> &'static str { + "foo" + } + Some("foo").expect(&get_string()); //~^ expect_fun_call Some("foo").expect(get_string().as_ref()); @@ -101,6 +105,15 @@ fn main() { //~^ expect_fun_call Some("foo").expect(get_non_static_str(&0)); //~^ expect_fun_call + + Some("foo").expect(const_evaluable()); + //~^ expect_fun_call + + const { + Some("foo").expect(const_evaluable()); + } + + Some("foo").expect(const { const_evaluable() }); } //Issue #3839 @@ -122,4 +135,15 @@ fn main() { let format_capture_and_value: Option<i32> = None; format_capture_and_value.expect(&format!("{error_code}, {}", 1)); //~^ expect_fun_call + + // Issue #15056 + let a = false; + Some(5).expect(if a { "a" } else { "b" }); + + let return_in_expect: Option<i32> = None; + return_in_expect.expect(if true { + "Error" + } else { + return; + }); } diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr index 36713196cb9..0692ecb4862 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.stderr +++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr @@ -38,58 +38,64 @@ LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:93:21 + --> tests/ui/expect_fun_call.rs:97:21 | LL | Some("foo").expect(&get_string()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_string()))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:95:21 + --> tests/ui/expect_fun_call.rs:99:21 | LL | Some("foo").expect(get_string().as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_string()))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:97:21 + --> tests/ui/expect_fun_call.rs:101:21 | LL | Some("foo").expect(get_string().as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_string()))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:100:21 + --> tests/ui/expect_fun_call.rs:104:21 | LL | Some("foo").expect(get_static_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_static_str()))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:102:21 + --> tests/ui/expect_fun_call.rs:106:21 | LL | Some("foo").expect(get_non_static_str(&0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", get_non_static_str(&0)))` + +error: function call inside of `expect` + --> tests/ui/expect_fun_call.rs:109:21 + | +LL | Some("foo").expect(const_evaluable()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{}", const_evaluable()))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:107:16 + --> tests/ui/expect_fun_call.rs:120:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:114:17 + --> tests/ui/expect_fun_call.rs:127:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:119:20 + --> tests/ui/expect_fun_call.rs:132:20 | LL | format_capture.expect(&format!("{error_code}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:123:30 + --> tests/ui/expect_fun_call.rs:136:30 | LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` -error: aborting due to 15 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed index b3e112f19eb..d370b85a67e 100644 --- a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed +++ b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed @@ -89,3 +89,24 @@ fn issue11503() { let _: Vec<usize> = bools.iter().enumerate().filter(|&(i, b)| ****b).map(|(i, b)| i).collect(); //~^ filter_map_bool_then } + +fn issue15047() { + #[derive(Clone, Copy)] + enum MyEnum { + A, + B, + C, + } + + macro_rules! foo { + ($e:expr) => { + $e + 1 + }; + } + + let x = 1; + let _ = [(MyEnum::A, "foo", 1i32)] + .iter() + .filter(|&(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar"))).map(|(t, s, i)| foo!(x)); + //~^ filter_map_bool_then +} diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.rs b/src/tools/clippy/tests/ui/filter_map_bool_then.rs index d996b3cb3c5..12295cc2482 100644 --- a/src/tools/clippy/tests/ui/filter_map_bool_then.rs +++ b/src/tools/clippy/tests/ui/filter_map_bool_then.rs @@ -89,3 +89,24 @@ fn issue11503() { let _: Vec<usize> = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); //~^ filter_map_bool_then } + +fn issue15047() { + #[derive(Clone, Copy)] + enum MyEnum { + A, + B, + C, + } + + macro_rules! foo { + ($e:expr) => { + $e + 1 + }; + } + + let x = 1; + let _ = [(MyEnum::A, "foo", 1i32)] + .iter() + .filter_map(|(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar")).then(|| foo!(x))); + //~^ filter_map_bool_then +} diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr index aeb1baeb35e..edf6c655939 100644 --- a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr +++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr @@ -61,5 +61,11 @@ error: usage of `bool::then` in `filter_map` LL | let _: Vec<usize> = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| ****b).map(|(i, b)| i)` -error: aborting due to 10 previous errors +error: usage of `bool::then` in `filter_map` + --> tests/ui/filter_map_bool_then.rs:110:10 + | +LL | .filter_map(|(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar")).then(|| foo!(x))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar"))).map(|(t, s, i)| foo!(x))` + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/flat_map_identity.fixed b/src/tools/clippy/tests/ui/flat_map_identity.fixed index f6206232612..06a3eee9d84 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.fixed +++ b/src/tools/clippy/tests/ui/flat_map_identity.fixed @@ -16,3 +16,16 @@ fn main() { let _ = iterator.flatten(); //~^ flat_map_identity } + +fn issue15198() { + let x = [[1, 2], [3, 4]]; + // don't lint: this is an `Iterator<Item = &[i32, i32]>` + // match ergonomics makes the binding patterns into references + // so that its type changes to `Iterator<Item = [&i32, &i32]>` + let _ = x.iter().flat_map(|[x, y]| [x, y]); + let _ = x.iter().flat_map(|x| [x[0]]); + + // no match ergonomics for `[i32, i32]` + let _ = x.iter().copied().flatten(); + //~^ flat_map_identity +} diff --git a/src/tools/clippy/tests/ui/flat_map_identity.rs b/src/tools/clippy/tests/ui/flat_map_identity.rs index c59e749474e..1cab7d559d8 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.rs +++ b/src/tools/clippy/tests/ui/flat_map_identity.rs @@ -16,3 +16,16 @@ fn main() { let _ = iterator.flat_map(|x| return x); //~^ flat_map_identity } + +fn issue15198() { + let x = [[1, 2], [3, 4]]; + // don't lint: this is an `Iterator<Item = &[i32, i32]>` + // match ergonomics makes the binding patterns into references + // so that its type changes to `Iterator<Item = [&i32, &i32]>` + let _ = x.iter().flat_map(|[x, y]| [x, y]); + let _ = x.iter().flat_map(|x| [x[0]]); + + // no match ergonomics for `[i32, i32]` + let _ = x.iter().copied().flat_map(|[x, y]| [x, y]); + //~^ flat_map_identity +} diff --git a/src/tools/clippy/tests/ui/flat_map_identity.stderr b/src/tools/clippy/tests/ui/flat_map_identity.stderr index 75137f5d9e5..18c863bf96d 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.stderr +++ b/src/tools/clippy/tests/ui/flat_map_identity.stderr @@ -19,5 +19,11 @@ error: use of `flat_map` with an identity function LL | let _ = iterator.flat_map(|x| return x); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` -error: aborting due to 3 previous errors +error: use of `flat_map` with an identity function + --> tests/ui/flat_map_identity.rs:29:31 + | +LL | let _ = x.iter().copied().flat_map(|[x, y]| [x, y]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed index f774608712d..d14a805b666 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed @@ -122,3 +122,46 @@ const fn issue12103(x: u32) -> Option<u32> { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } } + +mod issue15257 { + struct Range { + start: u8, + end: u8, + } + + fn can_be_safely_rewrite(rs: &[&Range]) -> Option<Vec<u8>> { + (rs.len() == 1 && rs[0].start == rs[0].end).then(|| vec![rs[0].start]) + } + + fn reborrow_as_ptr(i: *mut i32) -> Option<*const i32> { + let modulo = unsafe { *i % 2 }; + (modulo == 0).then_some(i) + } + + fn reborrow_as_fn_ptr(i: i32) { + fn do_something(fn_: Option<fn(i32)>) { + todo!() + } + + fn item_fn(i: i32) { + todo!() + } + + do_something((i % 2 == 0).then_some(item_fn)); + } + + fn reborrow_as_fn_unsafe(i: i32) { + fn do_something(fn_: Option<unsafe fn(i32)>) { + todo!() + } + + fn item_fn(i: i32) { + todo!() + } + + do_something((i % 2 == 0).then_some(item_fn)); + + let closure_fn = |i: i32| {}; + do_something((i % 2 == 0).then_some(closure_fn)); + } +} diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs index 8b8ff0a6ea0..bb0072f3157 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs @@ -143,3 +143,71 @@ const fn issue12103(x: u32) -> Option<u32> { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } } + +mod issue15257 { + struct Range { + start: u8, + end: u8, + } + + fn can_be_safely_rewrite(rs: &[&Range]) -> Option<Vec<u8>> { + if rs.len() == 1 && rs[0].start == rs[0].end { + //~^ if_then_some_else_none + Some(vec![rs[0].start]) + } else { + None + } + } + + fn reborrow_as_ptr(i: *mut i32) -> Option<*const i32> { + let modulo = unsafe { *i % 2 }; + if modulo == 0 { + //~^ if_then_some_else_none + Some(i) + } else { + None + } + } + + fn reborrow_as_fn_ptr(i: i32) { + fn do_something(fn_: Option<fn(i32)>) { + todo!() + } + + fn item_fn(i: i32) { + todo!() + } + + do_something(if i % 2 == 0 { + //~^ if_then_some_else_none + Some(item_fn) + } else { + None + }); + } + + fn reborrow_as_fn_unsafe(i: i32) { + fn do_something(fn_: Option<unsafe fn(i32)>) { + todo!() + } + + fn item_fn(i: i32) { + todo!() + } + + do_something(if i % 2 == 0 { + //~^ if_then_some_else_none + Some(item_fn) + } else { + None + }); + + let closure_fn = |i: i32| {}; + do_something(if i % 2 == 0 { + //~^ if_then_some_else_none + Some(closure_fn) + } else { + None + }); + } +} diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr index 71285574ef2..c2e624a0a73 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr @@ -58,5 +58,63 @@ error: this could be simplified with `bool::then` LL | if s == "1" { Some(true) } else { None } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(s == "1").then(|| true)` -error: aborting due to 6 previous errors +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:154:9 + | +LL | / if rs.len() == 1 && rs[0].start == rs[0].end { +LL | | +LL | | Some(vec![rs[0].start]) +LL | | } else { +LL | | None +LL | | } + | |_________^ help: try: `(rs.len() == 1 && rs[0].start == rs[0].end).then(|| vec![rs[0].start])` + +error: this could be simplified with `bool::then_some` + --> tests/ui/if_then_some_else_none.rs:164:9 + | +LL | / if modulo == 0 { +LL | | +LL | | Some(i) +LL | | } else { +LL | | None +LL | | } + | |_________^ help: try: `(modulo == 0).then_some(i)` + +error: this could be simplified with `bool::then_some` + --> tests/ui/if_then_some_else_none.rs:181:22 + | +LL | do_something(if i % 2 == 0 { + | ______________________^ +LL | | +LL | | Some(item_fn) +LL | | } else { +LL | | None +LL | | }); + | |_________^ help: try: `(i % 2 == 0).then_some(item_fn)` + +error: this could be simplified with `bool::then_some` + --> tests/ui/if_then_some_else_none.rs:198:22 + | +LL | do_something(if i % 2 == 0 { + | ______________________^ +LL | | +LL | | Some(item_fn) +LL | | } else { +LL | | None +LL | | }); + | |_________^ help: try: `(i % 2 == 0).then_some(item_fn)` + +error: this could be simplified with `bool::then_some` + --> tests/ui/if_then_some_else_none.rs:206:22 + | +LL | do_something(if i % 2 == 0 { + | ______________________^ +LL | | +LL | | Some(closure_fn) +LL | | } else { +LL | | None +LL | | }); + | |_________^ help: try: `(i % 2 == 0).then_some(closure_fn)` + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.rs b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.rs new file mode 100644 index 00000000000..be04299a6ab --- /dev/null +++ b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.rs @@ -0,0 +1,35 @@ +#![warn(clippy::if_then_some_else_none)] +#![allow(clippy::manual_is_multiple_of)] + +mod issue15257 { + use std::pin::Pin; + + #[derive(Default)] + pub struct Foo {} + pub trait Bar {} + impl Bar for Foo {} + + fn pointer_unsized_coercion(i: u32) -> Option<Box<dyn Bar>> { + if i % 2 == 0 { + //~^ if_then_some_else_none + Some(Box::new(Foo::default())) + } else { + None + } + } + + fn reborrow_as_pin(i: Pin<&mut i32>) { + use std::ops::Rem; + + fn do_something(i: Option<&i32>) { + todo!() + } + + do_something(if i.rem(2) == 0 { + //~^ if_then_some_else_none + Some(&i) + } else { + None + }); + } +} diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.stderr new file mode 100644 index 00000000000..f77ce7910e7 --- /dev/null +++ b/src/tools/clippy/tests/ui/if_then_some_else_none_unfixable.stderr @@ -0,0 +1,28 @@ +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none_unfixable.rs:13:9 + | +LL | / if i % 2 == 0 { +LL | | +LL | | Some(Box::new(Foo::default())) +LL | | } else { +LL | | None +LL | | } + | |_________^ + | + = note: `-D clippy::if-then-some-else-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]` + +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none_unfixable.rs:28:22 + | +LL | do_something(if i.rem(2) == 0 { + | ______________________^ +LL | | +LL | | Some(&i) +LL | | } else { +LL | | None +LL | | }); + | |_________^ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.rs b/src/tools/clippy/tests/ui/incompatible_msrv.rs index 99101b2bb8f..f7f21e1850d 100644 --- a/src/tools/clippy/tests/ui/incompatible_msrv.rs +++ b/src/tools/clippy/tests/ui/incompatible_msrv.rs @@ -1,8 +1,10 @@ #![warn(clippy::incompatible_msrv)] #![feature(custom_inner_attributes)] -#![feature(panic_internals)] +#![allow(stable_features)] +#![feature(strict_provenance)] // For use in test #![clippy::msrv = "1.3.0"] +use std::cell::Cell; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::future::Future; @@ -13,6 +15,8 @@ fn foo() { let mut map: HashMap<&str, u32> = HashMap::new(); assert_eq!(map.entry("poneyland").key(), &"poneyland"); //~^ incompatible_msrv + //~| NOTE: `-D clippy::incompatible-msrv` implied by `-D warnings` + //~| HELP: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]` if let Entry::Vacant(v) = map.entry("poneyland") { v.into_key(); @@ -23,6 +27,18 @@ fn foo() { //~^ incompatible_msrv } +#[clippy::msrv = "1.2.0"] +static NO_BODY_BAD_MSRV: Option<Duration> = None; +//~^ incompatible_msrv + +static NO_BODY_GOOD_MSRV: Option<Duration> = None; + +#[clippy::msrv = "1.2.0"] +fn bad_type_msrv() { + let _: Option<Duration> = None; + //~^ incompatible_msrv +} + #[test] fn test() { sleep(Duration::new(1, 0)); @@ -43,21 +59,22 @@ fn core_special_treatment(p: bool) { // But still lint code calling `core` functions directly if p { - core::panicking::panic("foo"); - //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0` + let _ = core::iter::once_with(|| 0); + //~^ incompatible_msrv } // Lint code calling `core` from non-`core` macros macro_rules! my_panic { ($msg:expr) => { - core::panicking::panic($msg) - }; //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0` + let _ = core::iter::once_with(|| $msg); + //~^ incompatible_msrv + }; } my_panic!("foo"); // Lint even when the macro comes from `core` and calls `core` functions - assert!(core::panicking::panic("out of luck")); - //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0` + assert!(core::iter::once_with(|| 0).next().is_some()); + //~^ incompatible_msrv } #[clippy::msrv = "1.26.0"] @@ -70,7 +87,85 @@ fn lang_items() { #[clippy::msrv = "1.80.0"] fn issue14212() { let _ = std::iter::repeat_n((), 5); - //~^ ERROR: is `1.80.0` but this item is stable since `1.82.0` + //~^ incompatible_msrv +} + +#[clippy::msrv = "1.0.0"] +fn cstr_and_cstring_ok() { + let _: Option<&'static std::ffi::CStr> = None; + let _: Option<std::ffi::CString> = None; +} + +fn local_msrv_change_suggestion() { + let _ = std::iter::repeat_n((), 5); + //~^ incompatible_msrv + + #[cfg(any(test, not(test)))] + { + let _ = std::iter::repeat_n((), 5); + //~^ incompatible_msrv + //~| NOTE: you may want to conditionally increase the MSRV + + // Emit the additional note only once + let _ = std::iter::repeat_n((), 5); + //~^ incompatible_msrv + } +} + +#[clippy::msrv = "1.78.0"] +fn feature_enable_14425(ptr: *const u8) -> usize { + // Do not warn, because it is enabled through a feature even though + // it is stabilized only since Rust 1.84.0. + let r = ptr.addr(); + + // Warn about this which has been introduced in the same Rust version + // but is not allowed through a feature. + r.isqrt() + //~^ incompatible_msrv +} + +fn non_fn_items() { + let _ = std::io::ErrorKind::CrossesDevices; + //~^ incompatible_msrv +} + +#[clippy::msrv = "1.87.0"] +fn msrv_non_ok_in_const() { + { + let c = Cell::new(42); + _ = c.get(); + } + const { + let c = Cell::new(42); + _ = c.get(); + //~^ incompatible_msrv + } +} + +#[clippy::msrv = "1.88.0"] +fn msrv_ok_in_const() { + { + let c = Cell::new(42); + _ = c.get(); + } + const { + let c = Cell::new(42); + _ = c.get(); + } +} + +#[clippy::msrv = "1.86.0"] +fn enum_variant_not_ok() { + let _ = std::io::ErrorKind::InvalidFilename; + //~^ incompatible_msrv + let _ = const { std::io::ErrorKind::InvalidFilename }; + //~^ incompatible_msrv +} + +#[clippy::msrv = "1.87.0"] +fn enum_variant_ok() { + let _ = std::io::ErrorKind::InvalidFilename; + let _ = const { std::io::ErrorKind::InvalidFilename }; } fn main() {} diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.stderr b/src/tools/clippy/tests/ui/incompatible_msrv.stderr index 5ea2bb9cc58..e42360d296f 100644 --- a/src/tools/clippy/tests/ui/incompatible_msrv.stderr +++ b/src/tools/clippy/tests/ui/incompatible_msrv.stderr @@ -1,5 +1,5 @@ error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.10.0` - --> tests/ui/incompatible_msrv.rs:14:39 + --> tests/ui/incompatible_msrv.rs:16:39 | LL | assert_eq!(map.entry("poneyland").key(), &"poneyland"); | ^^^^^ @@ -8,45 +8,107 @@ LL | assert_eq!(map.entry("poneyland").key(), &"poneyland"); = help: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]` error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.12.0` - --> tests/ui/incompatible_msrv.rs:18:11 + --> tests/ui/incompatible_msrv.rs:22:11 | LL | v.into_key(); | ^^^^^^^^^^ error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0` - --> tests/ui/incompatible_msrv.rs:22:5 + --> tests/ui/incompatible_msrv.rs:26:5 | LL | sleep(Duration::new(1, 0)); | ^^^^^ -error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0` - --> tests/ui/incompatible_msrv.rs:46:9 +error: current MSRV (Minimum Supported Rust Version) is `1.2.0` but this item is stable since `1.3.0` + --> tests/ui/incompatible_msrv.rs:31:33 | -LL | core::panicking::panic("foo"); - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | static NO_BODY_BAD_MSRV: Option<Duration> = None; + | ^^^^^^^^ -error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0` - --> tests/ui/incompatible_msrv.rs:53:13 +error: current MSRV (Minimum Supported Rust Version) is `1.2.0` but this item is stable since `1.3.0` + --> tests/ui/incompatible_msrv.rs:38:19 | -LL | core::panicking::panic($msg) - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Option<Duration> = None; + | ^^^^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.43.0` + --> tests/ui/incompatible_msrv.rs:62:17 + | +LL | let _ = core::iter::once_with(|| 0); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.43.0` + --> tests/ui/incompatible_msrv.rs:69:21 + | +LL | let _ = core::iter::once_with(|| $msg); + | ^^^^^^^^^^^^^^^^^^^^^ ... LL | my_panic!("foo"); | ---------------- in this macro invocation | = note: this error originates in the macro `my_panic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0` - --> tests/ui/incompatible_msrv.rs:59:13 +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.43.0` + --> tests/ui/incompatible_msrv.rs:76:13 | -LL | assert!(core::panicking::panic("out of luck")); - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | assert!(core::iter::once_with(|| 0).next().is_some()); + | ^^^^^^^^^^^^^^^^^^^^^ error: current MSRV (Minimum Supported Rust Version) is `1.80.0` but this item is stable since `1.82.0` - --> tests/ui/incompatible_msrv.rs:72:13 + --> tests/ui/incompatible_msrv.rs:89:13 + | +LL | let _ = std::iter::repeat_n((), 5); + | ^^^^^^^^^^^^^^^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.82.0` + --> tests/ui/incompatible_msrv.rs:100:13 | LL | let _ = std::iter::repeat_n((), 5); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.82.0` + --> tests/ui/incompatible_msrv.rs:105:17 + | +LL | let _ = std::iter::repeat_n((), 5); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: you may want to conditionally increase the MSRV considered by Clippy using the `clippy::msrv` attribute + +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.82.0` + --> tests/ui/incompatible_msrv.rs:110:17 + | +LL | let _ = std::iter::repeat_n((), 5); + | ^^^^^^^^^^^^^^^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.78.0` but this item is stable since `1.84.0` + --> tests/ui/incompatible_msrv.rs:123:7 + | +LL | r.isqrt() + | ^^^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.85.0` + --> tests/ui/incompatible_msrv.rs:128:13 + | +LL | let _ = std::io::ErrorKind::CrossesDevices; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.87.0` but this item is stable in a `const` context since `1.88.0` + --> tests/ui/incompatible_msrv.rs:140:15 + | +LL | _ = c.get(); + | ^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.86.0` but this item is stable since `1.87.0` + --> tests/ui/incompatible_msrv.rs:159:13 + | +LL | let _ = std::io::ErrorKind::InvalidFilename; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.86.0` but this item is stable since `1.87.0` + --> tests/ui/incompatible_msrv.rs:161:21 + | +LL | let _ = const { std::io::ErrorKind::InvalidFilename }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr index 80ca5daa1d5..ac1ed27a6b3 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr +++ b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr @@ -12,7 +12,7 @@ LL | | } | = note: `-D clippy::large-enum-variant` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]` -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B([i32; 8000]), LL + B(Box<[i32; 8000]>), @@ -30,7 +30,7 @@ LL | | ContainingLargeEnum(LargeEnum), LL | | } | |_^ the entire enum is at least 32004 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - ContainingLargeEnum(LargeEnum), LL + ContainingLargeEnum(Box<LargeEnum>), @@ -49,7 +49,7 @@ LL | | StructLikeLittle { x: i32, y: i32 }, LL | | } | |_^ the entire enum is at least 70008 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), LL + ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), @@ -67,7 +67,7 @@ LL | | StructLikeLarge { x: [i32; 8000], y: i32 }, LL | | } | |_^ the entire enum is at least 32008 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - StructLikeLarge { x: [i32; 8000], y: i32 }, LL + StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, @@ -85,7 +85,7 @@ LL | | StructLikeLarge2 { x: [i32; 8000] }, LL | | } | |_^ the entire enum is at least 32004 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - StructLikeLarge2 { x: [i32; 8000] }, LL + StructLikeLarge2 { x: Box<[i32; 8000]> }, @@ -104,7 +104,7 @@ LL | | C([u8; 200]), LL | | } | |_^ the entire enum is at least 1256 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B([u8; 1255]), LL + B(Box<[u8; 1255]>), @@ -122,7 +122,7 @@ LL | | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; LL | | } | |_^ the entire enum is at least 70132 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), LL + ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), @@ -140,7 +140,7 @@ LL | | B(Struct2), LL | | } | |_^ the entire enum is at least 32004 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B(Struct2), LL + B(Box<Struct2>), @@ -158,7 +158,7 @@ LL | | B(Struct2), LL | | } | |_^ the entire enum is at least 32000 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B(Struct2), LL + B(Box<Struct2>), @@ -176,7 +176,7 @@ LL | | B(Struct2), LL | | } | |_^ the entire enum is at least 32000 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B(Struct2), LL + B(Box<Struct2>), @@ -199,7 +199,7 @@ note: boxing a variant would require the type no longer be `Copy` | LL | enum CopyableLargeEnum { | ^^^^^^^^^^^^^^^^^ -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum --> tests/ui/large_enum_variant.rs:118:5 | LL | B([u64; 8000]), @@ -222,7 +222,7 @@ note: boxing a variant would require the type no longer be `Copy` | LL | enum ManuallyCopyLargeEnum { | ^^^^^^^^^^^^^^^^^^^^^ -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum --> tests/ui/large_enum_variant.rs:124:5 | LL | B([u64; 8000]), @@ -245,7 +245,7 @@ note: boxing a variant would require the type no longer be `Copy` | LL | enum SomeGenericPossiblyCopyEnum<T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum --> tests/ui/large_enum_variant.rs:138:5 | LL | B([u64; 4000]), @@ -263,7 +263,7 @@ LL | | Large((T, [u8; 512])), LL | | } | |_^ the entire enum is at least 512 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Large((T, [u8; 512])), LL + Large(Box<(T, [u8; 512])>), @@ -281,7 +281,7 @@ LL | | Small(u8), LL | | } | |_^ the entire enum is at least 516 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Large([Foo<u64>; 64]), LL + Large(Box<[Foo<u64>; 64]>), @@ -299,7 +299,7 @@ LL | | Error(PossiblyLargeEnumWithConst<256>), LL | | } | |_^ the entire enum is at least 514 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Error(PossiblyLargeEnumWithConst<256>), LL + Error(Box<PossiblyLargeEnumWithConst<256>>), @@ -317,7 +317,7 @@ LL | | Recursive(Box<WithRecursion>), LL | | } | |_^ the entire enum is at least 516 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Large([u64; 64]), LL + Large(Box<[u64; 64]>), @@ -335,7 +335,7 @@ LL | | Error(WithRecursionAndGenerics<u64>), LL | | } | |_^ the entire enum is at least 516 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Error(WithRecursionAndGenerics<u64>), LL + Error(Box<WithRecursionAndGenerics<u64>>), diff --git a/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr index 559bdf2a2f5..d8199f9090f 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr +++ b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr @@ -12,7 +12,7 @@ LL | | } | = note: `-D clippy::large-enum-variant` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]` -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B([i32; 8000]), LL + B(Box<[i32; 8000]>), @@ -30,7 +30,7 @@ LL | | ContainingLargeEnum(LargeEnum), LL | | } | |_^ the entire enum is at least 32004 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - ContainingLargeEnum(LargeEnum), LL + ContainingLargeEnum(Box<LargeEnum>), @@ -49,7 +49,7 @@ LL | | StructLikeLittle { x: i32, y: i32 }, LL | | } | |_^ the entire enum is at least 70008 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), LL + ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), @@ -67,7 +67,7 @@ LL | | StructLikeLarge { x: [i32; 8000], y: i32 }, LL | | } | |_^ the entire enum is at least 32008 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - StructLikeLarge { x: [i32; 8000], y: i32 }, LL + StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, @@ -85,7 +85,7 @@ LL | | StructLikeLarge2 { x: [i32; 8000] }, LL | | } | |_^ the entire enum is at least 32004 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - StructLikeLarge2 { x: [i32; 8000] }, LL + StructLikeLarge2 { x: Box<[i32; 8000]> }, @@ -104,7 +104,7 @@ LL | | C([u8; 200]), LL | | } | |_^ the entire enum is at least 1256 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B([u8; 1255]), LL + B(Box<[u8; 1255]>), @@ -122,7 +122,7 @@ LL | | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; LL | | } | |_^ the entire enum is at least 70132 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), LL + ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), @@ -140,7 +140,7 @@ LL | | B(Struct2), LL | | } | |_^ the entire enum is at least 32004 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B(Struct2), LL + B(Box<Struct2>), @@ -158,7 +158,7 @@ LL | | B(Struct2), LL | | } | |_^ the entire enum is at least 32000 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B(Struct2), LL + B(Box<Struct2>), @@ -176,7 +176,7 @@ LL | | B(Struct2), LL | | } | |_^ the entire enum is at least 32000 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - B(Struct2), LL + B(Box<Struct2>), @@ -199,7 +199,7 @@ note: boxing a variant would require the type no longer be `Copy` | LL | enum CopyableLargeEnum { | ^^^^^^^^^^^^^^^^^ -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum --> tests/ui/large_enum_variant.rs:118:5 | LL | B([u64; 8000]), @@ -222,7 +222,7 @@ note: boxing a variant would require the type no longer be `Copy` | LL | enum ManuallyCopyLargeEnum { | ^^^^^^^^^^^^^^^^^^^^^ -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum --> tests/ui/large_enum_variant.rs:124:5 | LL | B([u64; 8000]), @@ -245,7 +245,7 @@ note: boxing a variant would require the type no longer be `Copy` | LL | enum SomeGenericPossiblyCopyEnum<T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum --> tests/ui/large_enum_variant.rs:138:5 | LL | B([u64; 4000]), @@ -263,7 +263,7 @@ LL | | Large((T, [u8; 512])), LL | | } | |_^ the entire enum is at least 512 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Large((T, [u8; 512])), LL + Large(Box<(T, [u8; 512])>), @@ -281,7 +281,7 @@ LL | | Small(u8), LL | | } | |_^ the entire enum is at least 520 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Large([Foo<u64>; 64]), LL + Large(Box<[Foo<u64>; 64]>), @@ -299,7 +299,7 @@ LL | | Error(PossiblyLargeEnumWithConst<256>), LL | | } | |_^ the entire enum is at least 514 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Error(PossiblyLargeEnumWithConst<256>), LL + Error(Box<PossiblyLargeEnumWithConst<256>>), @@ -317,7 +317,7 @@ LL | | Recursive(Box<WithRecursion>), LL | | } | |_^ the entire enum is at least 520 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Large([u64; 64]), LL + Large(Box<[u64; 64]>), @@ -335,7 +335,7 @@ LL | | Error(WithRecursionAndGenerics<u64>), LL | | } | |_^ the entire enum is at least 520 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - Error(WithRecursionAndGenerics<u64>), LL + Error(Box<WithRecursionAndGenerics<u64>>), @@ -353,7 +353,7 @@ LL | | _SmallBoi(u8), LL | | } | |_____^ the entire enum is at least 296 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - BigBoi(PublishWithBytes), LL + BigBoi(Box<PublishWithBytes>), @@ -371,7 +371,7 @@ LL | | _SmallBoi(u8), LL | | } | |_____^ the entire enum is at least 224 bytes | -help: consider boxing the large fields to reduce the total size of the enum +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum | LL - BigBoi(PublishWithVec), LL + BigBoi(Box<PublishWithVec>), diff --git a/src/tools/clippy/tests/ui/large_enum_variant_no_std.rs b/src/tools/clippy/tests/ui/large_enum_variant_no_std.rs new file mode 100644 index 00000000000..ff0213155b6 --- /dev/null +++ b/src/tools/clippy/tests/ui/large_enum_variant_no_std.rs @@ -0,0 +1,8 @@ +#![no_std] +#![warn(clippy::large_enum_variant)] + +enum Myenum { + //~^ ERROR: large size difference between variants + Small(u8), + Large([u8; 1024]), +} diff --git a/src/tools/clippy/tests/ui/large_enum_variant_no_std.stderr b/src/tools/clippy/tests/ui/large_enum_variant_no_std.stderr new file mode 100644 index 00000000000..4f32e3e4835 --- /dev/null +++ b/src/tools/clippy/tests/ui/large_enum_variant_no_std.stderr @@ -0,0 +1,22 @@ +error: large size difference between variants + --> tests/ui/large_enum_variant_no_std.rs:4:1 + | +LL | / enum Myenum { +LL | | +LL | | Small(u8), + | | --------- the second-largest variant contains at least 1 bytes +LL | | Large([u8; 1024]), + | | ----------------- the largest variant contains at least 1024 bytes +LL | | } + | |_^ the entire enum is at least 1025 bytes + | +help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum + --> tests/ui/large_enum_variant_no_std.rs:7:5 + | +LL | Large([u8; 1024]), + | ^^^^^^^^^^^^^^^^^ + = note: `-D clippy::large-enum-variant` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed index 30bb549a9d6..d90e7bec027 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed @@ -79,9 +79,31 @@ fn main() { f64::consts::E; b!(); + std::primitive::i32::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead [(0, "", i128::MAX)]; //~^ ERROR: usage of a legacy numeric constant //~| HELP: use the associated constant instead + i32::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + assert_eq!(0, -i32::MAX); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + i128::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u32::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + i32::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + type Ω = i32; + Ω::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead } #[warn(clippy::legacy_numeric_constants)] diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs index d3878199055..4a2ef3f70c2 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs @@ -79,9 +79,31 @@ fn main() { f64::consts::E; b!(); + <std::primitive::i32>::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead [(0, "", std::i128::MAX)]; //~^ ERROR: usage of a legacy numeric constant //~| HELP: use the associated constant instead + (i32::max_value()); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + assert_eq!(0, -(i32::max_value())); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + (std::i128::MAX); + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + (<u32>::max_value()); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + ((i32::max_value)()); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + type Ω = i32; + Ω::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead } #[warn(clippy::legacy_numeric_constants)] diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr index 4d69b8165a3..0b4f32e0abc 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr @@ -72,10 +72,10 @@ LL | u32::MAX; | +++++ error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:50:10 + --> tests/ui/legacy_numeric_constants.rs:50:5 | LL | i32::max_value(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | help: use the associated constant instead | @@ -84,10 +84,10 @@ LL + i32::MAX; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:53:9 + --> tests/ui/legacy_numeric_constants.rs:53:5 | LL | u8::max_value(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | help: use the associated constant instead | @@ -96,10 +96,10 @@ LL + u8::MAX; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:56:9 + --> tests/ui/legacy_numeric_constants.rs:56:5 | LL | u8::min_value(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | help: use the associated constant instead | @@ -120,10 +120,10 @@ LL + u8::MIN; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:62:27 + --> tests/ui/legacy_numeric_constants.rs:62:5 | LL | ::std::primitive::u8::min_value(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: use the associated constant instead | @@ -132,10 +132,10 @@ LL + ::std::primitive::u8::MIN; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:65:26 + --> tests/ui/legacy_numeric_constants.rs:65:5 | LL | std::primitive::i32::max_value(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: use the associated constant instead | @@ -171,8 +171,20 @@ LL - let x = std::u64::MAX; LL + let x = u64::MAX; | +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:82:5 + | +LL | <std::primitive::i32>::max_value(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL - <std::primitive::i32>::max_value(); +LL + std::primitive::i32::MAX; + | + error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:82:14 + --> tests/ui/legacy_numeric_constants.rs:85:14 | LL | [(0, "", std::i128::MAX)]; | ^^^^^^^^^^^^^^ @@ -183,8 +195,80 @@ LL - [(0, "", std::i128::MAX)]; LL + [(0, "", i128::MAX)]; | +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:88:5 + | +LL | (i32::max_value()); + | ^^^^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL - (i32::max_value()); +LL + i32::MAX; + | + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:91:20 + | +LL | assert_eq!(0, -(i32::max_value())); + | ^^^^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL - assert_eq!(0, -(i32::max_value())); +LL + assert_eq!(0, -i32::MAX); + | + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:94:5 + | +LL | (std::i128::MAX); + | ^^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL - (std::i128::MAX); +LL + i128::MAX; + | + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:97:5 + | +LL | (<u32>::max_value()); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL - (<u32>::max_value()); +LL + u32::MAX; + | + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:100:5 + | +LL | ((i32::max_value)()); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL - ((i32::max_value)()); +LL + i32::MAX; + | + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:104:5 + | +LL | Ω::max_value(); + | ^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL - Ω::max_value(); +LL + Ω::MAX; + | + error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:116:5 + --> tests/ui/legacy_numeric_constants.rs:138:5 | LL | std::u32::MAX; | ^^^^^^^^^^^^^ @@ -195,5 +279,5 @@ LL - std::u32::MAX; LL + u32::MAX; | -error: aborting due to 16 previous errors +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.fixed b/src/tools/clippy/tests/ui/manual_abs_diff.fixed index f1b1278ea6d..2766942140c 100644 --- a/src/tools/clippy/tests/ui/manual_abs_diff.fixed +++ b/src/tools/clippy/tests/ui/manual_abs_diff.fixed @@ -104,3 +104,7 @@ fn non_primitive_ty() { let (a, b) = (S(10), S(20)); let _ = if a < b { b - a } else { a - b }; } + +fn issue15254(a: &usize, b: &usize) -> usize { + b.abs_diff(*a) +} diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.rs b/src/tools/clippy/tests/ui/manual_abs_diff.rs index 60ef819c12d..2c408f2be37 100644 --- a/src/tools/clippy/tests/ui/manual_abs_diff.rs +++ b/src/tools/clippy/tests/ui/manual_abs_diff.rs @@ -114,3 +114,12 @@ fn non_primitive_ty() { let (a, b) = (S(10), S(20)); let _ = if a < b { b - a } else { a - b }; } + +fn issue15254(a: &usize, b: &usize) -> usize { + if a < b { + //~^ manual_abs_diff + b - a + } else { + a - b + } +} diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.stderr b/src/tools/clippy/tests/ui/manual_abs_diff.stderr index c14c1dc830f..bb6d312b435 100644 --- a/src/tools/clippy/tests/ui/manual_abs_diff.stderr +++ b/src/tools/clippy/tests/ui/manual_abs_diff.stderr @@ -79,5 +79,16 @@ error: manual absolute difference pattern without using `abs_diff` LL | let _ = if a > b { (a - b) as u32 } else { (b - a) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)` -error: aborting due to 11 previous errors +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:119:5 + | +LL | / if a < b { +LL | | +LL | | b - a +LL | | } else { +LL | | a - b +LL | | } + | |_____^ help: replace with `abs_diff`: `b.abs_diff(*a)` + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr index 8cedf2c6863..221cddf069d 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr @@ -189,5 +189,23 @@ LL - }; LL + const BAR: () = assert!(!(N == 0), ); | -error: aborting due to 10 previous errors +error: only a `panic!` in `if`-then statement + --> tests/ui/manual_assert.rs:116:5 + | +LL | / if !is_x86_feature_detected!("ssse3") { +LL | | +LL | | panic!("SSSE3 is not supported"); +LL | | } + | |_____^ + | +help: try instead + | +LL - if !is_x86_feature_detected!("ssse3") { +LL - +LL - panic!("SSSE3 is not supported"); +LL - } +LL + assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported"); + | + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr index 8cedf2c6863..221cddf069d 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr @@ -189,5 +189,23 @@ LL - }; LL + const BAR: () = assert!(!(N == 0), ); | -error: aborting due to 10 previous errors +error: only a `panic!` in `if`-then statement + --> tests/ui/manual_assert.rs:116:5 + | +LL | / if !is_x86_feature_detected!("ssse3") { +LL | | +LL | | panic!("SSSE3 is not supported"); +LL | | } + | |_____^ + | +help: try instead + | +LL - if !is_x86_feature_detected!("ssse3") { +LL - +LL - panic!("SSSE3 is not supported"); +LL - } +LL + assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported"); + | + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs index 46a42c3d00a..ab02bd5f5e5 100644 --- a/src/tools/clippy/tests/ui/manual_assert.rs +++ b/src/tools/clippy/tests/ui/manual_assert.rs @@ -105,3 +105,17 @@ fn issue12505() { }; } } + +fn issue15227(left: u64, right: u64) -> u64 { + macro_rules! is_x86_feature_detected { + ($feature:literal) => { + $feature.len() > 0 && $feature.starts_with("ss") + }; + } + + if !is_x86_feature_detected!("ssse3") { + //~^ manual_assert + panic!("SSSE3 is not supported"); + } + unsafe { todo!() } +} diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed index 6735b99f298..03f75e725ed 100644 --- a/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed +++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed @@ -23,3 +23,81 @@ fn f(a: u64, b: u64) { fn g(a: u64, b: u64) { let _ = a % b == 0; } + +fn needs_deref(a: &u64, b: &u64) { + let _ = a.is_multiple_of(*b); //~ manual_is_multiple_of +} + +fn closures(a: u64, b: u64) { + // Do not lint, types are ambiguous at this point + let cl = |a, b| a % b == 0; + let _ = cl(a, b); + + // Do not lint, types are ambiguous at this point + let cl = |a: _, b: _| a % b == 0; + let _ = cl(a, b); + + // Type of `a` is enough + let cl = |a: u64, b| a.is_multiple_of(b); //~ manual_is_multiple_of + let _ = cl(a, b); + + // Type of `a` is enough + let cl = |a: &u64, b| a.is_multiple_of(b); //~ manual_is_multiple_of + let _ = cl(&a, b); + + // Type of `b` is not enough + let cl = |a, b: u64| a % b == 0; + let _ = cl(&a, b); +} + +fn any_rem<T: std::ops::Rem<Output = u32>>(a: T, b: T) { + // An arbitrary `Rem` implementation should not lint + let _ = a % b == 0; +} + +mod issue15103 { + fn foo() -> Option<u64> { + let mut n: u64 = 150_000_000; + + (2..).find(|p| { + while n.is_multiple_of(*p) { + //~^ manual_is_multiple_of + n /= p; + } + n <= 1 + }) + } + + const fn generate_primes<const N: usize>() -> [u64; N] { + let mut result = [0; N]; + if N == 0 { + return result; + } + result[0] = 2; + if N == 1 { + return result; + } + let mut idx = 1; + let mut p = 3; + while idx < N { + let mut j = 0; + while j < idx && p % result[j] != 0 { + j += 1; + } + if j == idx { + result[idx] = p; + idx += 1; + } + p += 1; + } + result + } + + fn bar() -> u32 { + let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n.is_multiple_of(*i)).sum() }; + //~^ manual_is_multiple_of + + let d = |n| (1..=n / 2).filter(|i| n % i == 0).sum(); + (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() + } +} diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.rs b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs index 00b638e4fd9..7b6fa64c843 100644 --- a/src/tools/clippy/tests/ui/manual_is_multiple_of.rs +++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs @@ -23,3 +23,81 @@ fn f(a: u64, b: u64) { fn g(a: u64, b: u64) { let _ = a % b == 0; } + +fn needs_deref(a: &u64, b: &u64) { + let _ = a % b == 0; //~ manual_is_multiple_of +} + +fn closures(a: u64, b: u64) { + // Do not lint, types are ambiguous at this point + let cl = |a, b| a % b == 0; + let _ = cl(a, b); + + // Do not lint, types are ambiguous at this point + let cl = |a: _, b: _| a % b == 0; + let _ = cl(a, b); + + // Type of `a` is enough + let cl = |a: u64, b| a % b == 0; //~ manual_is_multiple_of + let _ = cl(a, b); + + // Type of `a` is enough + let cl = |a: &u64, b| a % b == 0; //~ manual_is_multiple_of + let _ = cl(&a, b); + + // Type of `b` is not enough + let cl = |a, b: u64| a % b == 0; + let _ = cl(&a, b); +} + +fn any_rem<T: std::ops::Rem<Output = u32>>(a: T, b: T) { + // An arbitrary `Rem` implementation should not lint + let _ = a % b == 0; +} + +mod issue15103 { + fn foo() -> Option<u64> { + let mut n: u64 = 150_000_000; + + (2..).find(|p| { + while n % p == 0 { + //~^ manual_is_multiple_of + n /= p; + } + n <= 1 + }) + } + + const fn generate_primes<const N: usize>() -> [u64; N] { + let mut result = [0; N]; + if N == 0 { + return result; + } + result[0] = 2; + if N == 1 { + return result; + } + let mut idx = 1; + let mut p = 3; + while idx < N { + let mut j = 0; + while j < idx && p % result[j] != 0 { + j += 1; + } + if j == idx { + result[idx] = p; + idx += 1; + } + p += 1; + } + result + } + + fn bar() -> u32 { + let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n % i == 0).sum() }; + //~^ manual_is_multiple_of + + let d = |n| (1..=n / 2).filter(|i| n % i == 0).sum(); + (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() + } +} diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr index 0b1ae70c2a7..8523599ec40 100644 --- a/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr +++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr @@ -37,5 +37,35 @@ error: manual implementation of `.is_multiple_of()` LL | let _ = 0 < a % b; | ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)` -error: aborting due to 6 previous errors +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:28:13 + | +LL | let _ = a % b == 0; + | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(*b)` + +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:41:26 + | +LL | let cl = |a: u64, b| a % b == 0; + | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(b)` + +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:45:27 + | +LL | let cl = |a: &u64, b| a % b == 0; + | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(b)` + +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:63:19 + | +LL | while n % p == 0 { + | ^^^^^^^^^^ help: replace with: `n.is_multiple_of(*p)` + +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:97:58 + | +LL | let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n % i == 0).sum() }; + | ^^^^^^^^^^ help: replace with: `n.is_multiple_of(*i)` + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed index 83b2dac5fc5..b82d3e6d956 100644 --- a/src/tools/clippy/tests/ui/map_identity.fixed +++ b/src/tools/clippy/tests/ui/map_identity.fixed @@ -87,3 +87,15 @@ fn issue13904() { let _ = { it }.next(); //~^ map_identity } + +// same as `issue11764`, but for arrays +fn issue15198() { + let x = [[1, 2], [3, 4]]; + // don't lint: `&[i32; 2]` becomes `[&i32; 2]` + let _ = x.iter().map(|[x, y]| [x, y]); + let _ = x.iter().map(|x| [x[0]]).map(|[x]| x); + + // no match ergonomics for `[i32, i32]` + let _ = x.iter().copied(); + //~^ map_identity +} diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs index e839c551364..c295bf87270 100644 --- a/src/tools/clippy/tests/ui/map_identity.rs +++ b/src/tools/clippy/tests/ui/map_identity.rs @@ -93,3 +93,15 @@ fn issue13904() { let _ = { it }.map(|x| x).next(); //~^ map_identity } + +// same as `issue11764`, but for arrays +fn issue15198() { + let x = [[1, 2], [3, 4]]; + // don't lint: `&[i32; 2]` becomes `[&i32; 2]` + let _ = x.iter().map(|[x, y]| [x, y]); + let _ = x.iter().map(|x| [x[0]]).map(|[x]| x); + + // no match ergonomics for `[i32, i32]` + let _ = x.iter().copied().map(|[x, y]| [x, y]); + //~^ map_identity +} diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr index 9836f3b4cc5..9b624a0dc75 100644 --- a/src/tools/clippy/tests/ui/map_identity.stderr +++ b/src/tools/clippy/tests/ui/map_identity.stderr @@ -87,5 +87,11 @@ error: unnecessary map of the identity function LL | let _ = { it }.map(|x| x).next(); | ^^^^^^^^^^^ help: remove the call to `map` -error: aborting due to 13 previous errors +error: unnecessary map of the identity function + --> tests/ui/map_identity.rs:105:30 + | +LL | let _ = x.iter().copied().map(|[x, y]| [x, y]); + | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/missing_inline.rs b/src/tools/clippy/tests/ui/missing_inline.rs index c1801005b77..223c7447975 100644 --- a/src/tools/clippy/tests/ui/missing_inline.rs +++ b/src/tools/clippy/tests/ui/missing_inline.rs @@ -80,3 +80,20 @@ impl PubFoo { // do not lint this since users cannot control the external code #[derive(Debug)] pub struct S; + +pub mod issue15301 { + #[unsafe(no_mangle)] + pub extern "C" fn call_from_c() { + println!("Just called a Rust function from C!"); + } + + #[unsafe(no_mangle)] + pub extern "Rust" fn call_from_rust() { + println!("Just called a Rust function from Rust!"); + } + + #[unsafe(no_mangle)] + pub fn call_from_rust_no_extern() { + println!("Just called a Rust function from Rust!"); + } +} diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs index 2fde98d7927..5d16858bf85 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.rs +++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs @@ -55,3 +55,21 @@ pub mod foo { } fn main() {} + +pub mod issue14095 { + pub mod widget { + #[macro_export] + macro_rules! define_widget { + ($id:ident) => { + /* ... */ + }; + } + + #[macro_export] + macro_rules! widget_impl { + ($id:ident) => { + /* ... */ + }; + } + } +} diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed index 4c1d6b1ccb5..1e8589cf39d 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.fixed +++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed @@ -13,13 +13,15 @@ use std::sync::atomic::{AtomicBool, Ordering}; pub struct MyAtomic(AtomicBool); pub struct MyPure; -#[must_use] pub fn pure(i: u8) -> u8 { +#[must_use] +pub fn pure(i: u8) -> u8 { //~^ must_use_candidate i } impl MyPure { - #[must_use] pub fn inherent_pure(&self) -> u8 { + #[must_use] + pub fn inherent_pure(&self) -> u8 { //~^ must_use_candidate 0 } @@ -51,7 +53,8 @@ pub fn with_callback<F: Fn(u32) -> bool>(f: &F) -> bool { f(0) } -#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { +#[must_use] +pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { //~^ must_use_candidate true } @@ -64,7 +67,8 @@ pub fn atomics(b: &AtomicBool) -> bool { b.load(Ordering::SeqCst) } -#[must_use] pub fn rcd(_x: Rc<u32>) -> bool { +#[must_use] +pub fn rcd(_x: Rc<u32>) -> bool { //~^ must_use_candidate true } @@ -73,7 +77,8 @@ pub fn rcmut(_x: Rc<&mut u32>) -> bool { true } -#[must_use] pub fn arcd(_x: Arc<u32>) -> bool { +#[must_use] +pub fn arcd(_x: Arc<u32>) -> bool { //~^ must_use_candidate false } diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr index 590253d95f9..5ddbd026062 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.stderr +++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr @@ -1,35 +1,64 @@ error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:16:1 + --> tests/ui/must_use_candidates.rs:16:8 | LL | pub fn pure(i: u8) -> u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8` + | ^^^^ | = note: `-D clippy::must-use-candidate` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]` +help: add the attribute + | +LL + #[must_use] +LL | pub fn pure(i: u8) -> u8 { + | error: this method could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:22:5 + --> tests/ui/must_use_candidates.rs:22:12 | LL | pub fn inherent_pure(&self) -> u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8` + | ^^^^^^^^^^^^^ + | +help: add the attribute + | +LL ~ #[must_use] +LL ~ pub fn inherent_pure(&self) -> u8 { + | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:54:1 + --> tests/ui/must_use_candidates.rs:54:8 + | +LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { + | ^^^^^^^^^^^ + | +help: add the attribute | +LL + #[must_use] LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool` + | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:67:1 + --> tests/ui/must_use_candidates.rs:67:8 | LL | pub fn rcd(_x: Rc<u32>) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool` + | ^^^ + | +help: add the attribute + | +LL + #[must_use] +LL | pub fn rcd(_x: Rc<u32>) -> bool { + | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:76:1 + --> tests/ui/must_use_candidates.rs:76:8 | LL | pub fn arcd(_x: Arc<u32>) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool` + | ^^^^ + | +help: add the attribute + | +LL + #[must_use] +LL | pub fn arcd(_x: Arc<u32>) -> bool { + | error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed index a73aff55639..a6d64d9afc1 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed @@ -143,3 +143,9 @@ mod issue14734 { //~^ needless_for_each } } + +fn issue15256() { + let vec: Vec<i32> = Vec::new(); + for v in vec.iter() { println!("{v}"); } + //~^ needless_for_each +} diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs index d92f055d3f4..7e74d2b428f 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs @@ -143,3 +143,9 @@ mod issue14734 { //~^ needless_for_each } } + +fn issue15256() { + let vec: Vec<i32> = Vec::new(); + vec.iter().for_each(|v| println!("{v}")); + //~^ needless_for_each +} diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr index f8014456097..204cfa36b02 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr @@ -148,5 +148,11 @@ error: needless use of `for_each` LL | rows.iter().for_each(|x| do_something(x, 1u8)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in rows.iter() { do_something(x, 1u8); }` -error: aborting due to 10 previous errors +error: needless use of `for_each` + --> tests/ui/needless_for_each_fixable.rs:149:5 + | +LL | vec.iter().for_each(|v| println!("{v}")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for v in vec.iter() { println!("{v}"); }` + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs index 8a1c1be289c..70cf9fa7369 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop.rs +++ b/src/tools/clippy/tests/ui/needless_range_loop.rs @@ -185,3 +185,28 @@ mod issue_2496 { unimplemented!() } } + +fn needless_loop() { + use std::hint::black_box; + let x = [0; 64]; + for i in 0..64 { + let y = [0; 64]; + + black_box(x[i]); + black_box(y[i]); + } + + for i in 0..64 { + black_box(x[i]); + black_box([0; 64][i]); + } + + for i in 0..64 { + black_box(x[i]); + black_box([1, 2, 3, 4, 5, 6, 7, 8][i]); + } + + for i in 0..64 { + black_box([1, 2, 3, 4, 5, 6, 7, 8][i]); + } +} diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs index e0f54ef899b..48d4b8ad151 100644 --- a/src/tools/clippy/tests/ui/never_loop.rs +++ b/src/tools/clippy/tests/ui/never_loop.rs @@ -466,3 +466,35 @@ fn main() { test13(); test14(); } + +fn issue15059() { + 'a: for _ in 0..1 { + //~^ never_loop + break 'a; + } + + let mut b = 1; + 'a: for i in 0..1 { + //~^ never_loop + match i { + 0 => { + b *= 2; + break 'a; + }, + x => { + b += x; + break 'a; + }, + } + } + + #[allow(clippy::unused_unit)] + for v in 0..10 { + //~^ never_loop + break; + println!("{v}"); + // This is comment and should be kept + println!("This is a comment"); + () + } +} diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr index bc9a7ec48b4..54b463266a3 100644 --- a/src/tools/clippy/tests/ui/never_loop.stderr +++ b/src/tools/clippy/tests/ui/never_loop.stderr @@ -176,8 +176,10 @@ LL | | } | help: if you need the first element of the iterator, try writing | -LL - for v in 0..10 { -LL + if let Some(v) = (0..10).next() { +LL ~ if let Some(v) = (0..10).next() { +LL | +LL ~ +LL ~ | error: this loop never actually loops @@ -232,5 +234,68 @@ LL | | break 'inner; LL | | } | |_________^ -error: aborting due to 21 previous errors +error: this loop never actually loops + --> tests/ui/never_loop.rs:471:5 + | +LL | / 'a: for _ in 0..1 { +LL | | +LL | | break 'a; +LL | | } + | |_____^ + | +help: if you need the first element of the iterator, try writing + | +LL ~ if let Some(_) = (0..1).next() { +LL | +LL ~ + | + +error: this loop never actually loops + --> tests/ui/never_loop.rs:477:5 + | +LL | / 'a: for i in 0..1 { +LL | | +LL | | match i { +LL | | 0 => { +... | +LL | | } + | |_____^ + | +help: if you need the first element of the iterator, try writing + | +LL ~ if let Some(i) = (0..1).next() { +LL | +... +LL | b *= 2; +LL ~ +LL | }, +LL | x => { +LL | b += x; +LL ~ + | + +error: this loop never actually loops + --> tests/ui/never_loop.rs:492:5 + | +LL | / for v in 0..10 { +LL | | +LL | | break; +LL | | println!("{v}"); +... | +LL | | () +LL | | } + | |_____^ + | +help: if you need the first element of the iterator, try writing + | +LL ~ if let Some(v) = (0..10).next() { +LL | +LL ~ +LL ~ +LL | // This is comment and should be kept +LL ~ +LL ~ + | + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index bcd2602edb6..0a8525a12f5 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -283,6 +283,8 @@ mod issue8993 { let _ = Some(4).map_or_else(g, f); //~^ or_fun_call let _ = Some(4).map_or(0, f); + let _ = Some(4).map_or_else(|| "asd".to_string().len() as i32, f); + //~^ or_fun_call } } @@ -426,6 +428,8 @@ mod result_map_or { let _ = x.map_or_else(|_| g(), f); //~^ or_fun_call let _ = x.map_or(0, f); + let _ = x.map_or_else(|_| "asd".to_string().len() as i32, f); + //~^ or_fun_call } } diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index 8d1202ebf91..b4f9b950a7f 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -283,6 +283,8 @@ mod issue8993 { let _ = Some(4).map_or(g(), f); //~^ or_fun_call let _ = Some(4).map_or(0, f); + let _ = Some(4).map_or("asd".to_string().len() as i32, f); + //~^ or_fun_call } } @@ -426,6 +428,8 @@ mod result_map_or { let _ = x.map_or(g(), f); //~^ or_fun_call let _ = x.map_or(0, f); + let _ = x.map_or("asd".to_string().len() as i32, f); + //~^ or_fun_call } } diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index 585ee2d0e19..3e4df772668 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -154,62 +154,68 @@ error: function call inside of `map_or` LL | let _ = Some(4).map_or(g(), f); | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` +error: function call inside of `map_or` + --> tests/ui/or_fun_call.rs:286:25 + | +LL | let _ = Some(4).map_or("asd".to_string().len() as i32, f); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| "asd".to_string().len() as i32, f)` + error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:315:18 + --> tests/ui/or_fun_call.rs:317:18 | LL | with_new.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:319:28 + --> tests/ui/or_fun_call.rs:321:28 | LL | with_default_trait.unwrap_or_else(Default::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:323:27 + --> tests/ui/or_fun_call.rs:325:27 | LL | with_default_type.unwrap_or_else(u64::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:327:22 + --> tests/ui/or_fun_call.rs:329:22 | LL | real_default.unwrap_or_else(<FakeDefault as Default>::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `or_insert_with` to construct default value - --> tests/ui/or_fun_call.rs:331:23 + --> tests/ui/or_fun_call.rs:333:23 | LL | map.entry(42).or_insert_with(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert_with` to construct default value - --> tests/ui/or_fun_call.rs:335:25 + --> tests/ui/or_fun_call.rs:337:25 | LL | btree.entry(42).or_insert_with(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:339:25 + --> tests/ui/or_fun_call.rs:341:25 | LL | let _ = stringy.unwrap_or_else(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:381:17 + --> tests/ui/or_fun_call.rs:383:17 | LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:386:17 + --> tests/ui/or_fun_call.rs:388:17 | LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:391:17 + --> tests/ui/or_fun_call.rs:393:17 | LL | let _ = opt.unwrap_or({ | _________________^ @@ -229,52 +235,58 @@ LL ~ }); | error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:397:17 + --> tests/ui/or_fun_call.rs:399:17 | LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:402:17 + --> tests/ui/or_fun_call.rs:404:17 | LL | let _ = opt.unwrap_or({ i32::default() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:409:21 + --> tests/ui/or_fun_call.rs:411:21 | LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })` error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:424:19 + --> tests/ui/or_fun_call.rs:426:19 | LL | let _ = x.map_or(g(), |v| v); | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)` error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:426:19 + --> tests/ui/or_fun_call.rs:428:19 | LL | let _ = x.map_or(g(), f); | ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)` +error: function call inside of `map_or` + --> tests/ui/or_fun_call.rs:431:19 + | +LL | let _ = x.map_or("asd".to_string().len() as i32, f); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| "asd".to_string().len() as i32, f)` + error: function call inside of `get_or_insert` - --> tests/ui/or_fun_call.rs:438:15 + --> tests/ui/or_fun_call.rs:442:15 | LL | let _ = x.get_or_insert(g()); | ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)` error: function call inside of `and` - --> tests/ui/or_fun_call.rs:448:15 + --> tests/ui/or_fun_call.rs:452:15 | LL | let _ = x.and(g()); | ^^^^^^^^ help: try: `and_then(|_| g())` error: function call inside of `and` - --> tests/ui/or_fun_call.rs:458:15 + --> tests/ui/or_fun_call.rs:462:15 | LL | let _ = x.and(g()); | ^^^^^^^^ help: try: `and_then(|_| g())` -error: aborting due to 43 previous errors +error: aborting due to 45 previous errors diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/auxiliary/external.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/auxiliary/external.rs new file mode 100644 index 00000000000..cd27c5c74aa --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/auxiliary/external.rs @@ -0,0 +1,13 @@ +//! **FAKE** external macro crate. + +#[macro_export] +macro_rules! macro_with_match { + ( $p:pat ) => { + let something = (); + + match &something { + $p => true, + _ => false, + } + }; +} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs index 49ea1d3f7a6..aa988a577df 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs @@ -6,6 +6,9 @@ clippy::single_match )] +//@aux-build:external.rs +use external::macro_with_match; + fn main() {} fn syntax_match() { @@ -159,3 +162,9 @@ fn macro_expansion() { let value = &Some(23); matching_macro!(value); } + +fn external_macro_expansion() { + macro_with_match! { + () + }; +} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr index cd604d604c1..636841e0a21 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr @@ -1,5 +1,5 @@ error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:16:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:19:9 | LL | Some(_) => (), | ^^^^^^^ @@ -9,7 +9,7 @@ LL | Some(_) => (), = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:36:12 + --> tests/ui/pattern_type_mismatch/syntax.rs:39:12 | LL | if let Some(_) = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let Some(_) = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:48:15 + --> tests/ui/pattern_type_mismatch/syntax.rs:51:15 | LL | while let Some(_) = ref_value { | ^^^^^^^ @@ -25,7 +25,7 @@ LL | while let Some(_) = ref_value { = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:68:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:71:9 | LL | for (_a, _b) in slice.iter() {} | ^^^^^^^^ @@ -33,7 +33,7 @@ LL | for (_a, _b) in slice.iter() {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:79:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:82:9 | LL | let (_n, _m) = ref_value; | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | let (_n, _m) = ref_value; = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:89:12 + --> tests/ui/pattern_type_mismatch/syntax.rs:92:12 | LL | fn foo((_a, _b): &(i32, i32)) {} | ^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn foo((_a, _b): &(i32, i32)) {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:104:10 + --> tests/ui/pattern_type_mismatch/syntax.rs:107:10 | LL | foo(|(_a, _b)| ()); | ^^^^^^^^ @@ -57,7 +57,7 @@ LL | foo(|(_a, _b)| ()); = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:121:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:124:9 | LL | Some(_) => (), | ^^^^^^^ @@ -65,7 +65,7 @@ LL | Some(_) => (), = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:142:17 + --> tests/ui/pattern_type_mismatch/syntax.rs:145:17 | LL | Some(_) => (), | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 578641e910d..be14e0762ff 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -123,7 +123,7 @@ fn test_cow_with_ref(c: &Cow<[i32]>) {} //~^ ptr_arg fn test_cow(c: Cow<[i32]>) { - let _c = c; + let d = c; } trait Foo2 { @@ -141,36 +141,36 @@ mod issue_5644 { use std::path::PathBuf; fn allowed( - #[allow(clippy::ptr_arg)] _v: &Vec<u32>, - #[allow(clippy::ptr_arg)] _s: &String, - #[allow(clippy::ptr_arg)] _p: &PathBuf, - #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, - #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>, + #[allow(clippy::ptr_arg)] v: &Vec<u32>, + #[allow(clippy::ptr_arg)] s: &String, + #[allow(clippy::ptr_arg)] p: &PathBuf, + #[allow(clippy::ptr_arg)] c: &Cow<[i32]>, + #[expect(clippy::ptr_arg)] expect: &Cow<[i32]>, ) { } - fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {} + fn some_allowed(#[allow(clippy::ptr_arg)] v: &Vec<u32>, s: &String) {} //~^ ptr_arg struct S; impl S { fn allowed( - #[allow(clippy::ptr_arg)] _v: &Vec<u32>, - #[allow(clippy::ptr_arg)] _s: &String, - #[allow(clippy::ptr_arg)] _p: &PathBuf, - #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, - #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>, + #[allow(clippy::ptr_arg)] v: &Vec<u32>, + #[allow(clippy::ptr_arg)] s: &String, + #[allow(clippy::ptr_arg)] p: &PathBuf, + #[allow(clippy::ptr_arg)] c: &Cow<[i32]>, + #[expect(clippy::ptr_arg)] expect: &Cow<[i32]>, ) { } } trait T { fn allowed( - #[allow(clippy::ptr_arg)] _v: &Vec<u32>, - #[allow(clippy::ptr_arg)] _s: &String, - #[allow(clippy::ptr_arg)] _p: &PathBuf, - #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, - #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>, + #[allow(clippy::ptr_arg)] v: &Vec<u32>, + #[allow(clippy::ptr_arg)] s: &String, + #[allow(clippy::ptr_arg)] p: &PathBuf, + #[allow(clippy::ptr_arg)] c: &Cow<[i32]>, + #[expect(clippy::ptr_arg)] expect: &Cow<[i32]>, ) { } } @@ -182,22 +182,22 @@ mod issue6509 { fn foo_vec(vec: &Vec<u8>) { //~^ ptr_arg - let _ = vec.clone().pop(); - let _ = vec.clone().clone(); + let a = vec.clone().pop(); + let b = vec.clone().clone(); } fn foo_path(path: &PathBuf) { //~^ ptr_arg - let _ = path.clone().pop(); - let _ = path.clone().clone(); + let c = path.clone().pop(); + let d = path.clone().clone(); } - fn foo_str(str: &PathBuf) { + fn foo_str(str: &String) { //~^ ptr_arg - let _ = str.clone().pop(); - let _ = str.clone().clone(); + let e = str.clone().pop(); + let f = str.clone().clone(); } } @@ -340,8 +340,8 @@ mod issue_13308 { ToOwned::clone_into(source, destination); } - fn h1(_: &<String as Deref>::Target) {} - fn h2<T: Deref>(_: T, _: &T::Target) {} + fn h1(x: &<String as Deref>::Target) {} + fn h2<T: Deref>(x: T, y: &T::Target) {} // Other cases that are still ok to lint and ideally shouldn't regress fn good(v1: &String, v2: &String) { @@ -352,3 +352,91 @@ mod issue_13308 { h2(String::new(), v2); } } + +mod issue_13489_and_13728 { + // This is a no-lint from now on. + fn foo(_x: &Vec<i32>) { + todo!(); + } + + // But this still gives us a lint. + fn foo_used(x: &Vec<i32>) { + //~^ ptr_arg + + todo!(); + } + + // This is also a no-lint from now on. + fn foo_local(x: &Vec<i32>) { + let _y = x; + + todo!(); + } + + // But this still gives us a lint. + fn foo_local_used(x: &Vec<i32>) { + //~^ ptr_arg + + let y = x; + + todo!(); + } + + // This only lints once from now on. + fn foofoo(_x: &Vec<i32>, y: &String) { + //~^ ptr_arg + + todo!(); + } + + // And this is also a no-lint from now on. + fn foofoo_local(_x: &Vec<i32>, y: &String) { + let _z = y; + + todo!(); + } +} + +mod issue_13489_and_13728_mut { + // This is a no-lint from now on. + fn bar(_x: &mut Vec<u32>) { + todo!() + } + + // But this still gives us a lint. + fn bar_used(x: &mut Vec<u32>) { + //~^ ptr_arg + + todo!() + } + + // This is also a no-lint from now on. + fn bar_local(x: &mut Vec<u32>) { + let _y = x; + + todo!() + } + + // But this still gives us a lint. + fn bar_local_used(x: &mut Vec<u32>) { + //~^ ptr_arg + + let y = x; + + todo!() + } + + // This only lints once from now on. + fn barbar(_x: &mut Vec<u32>, y: &mut String) { + //~^ ptr_arg + + todo!() + } + + // And this is also a no-lint from now on. + fn barbar_local(_x: &mut Vec<u32>, y: &mut String) { + let _z = y; + + todo!() + } +} diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index fd9ceddfe11..87235057349 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -127,10 +127,10 @@ LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:152:66 + --> tests/ui/ptr_arg.rs:152:64 | -LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {} - | ^^^^^^^ help: change this to: `&str` +LL | fn some_allowed(#[allow(clippy::ptr_arg)] v: &Vec<u32>, s: &String) {} + | ^^^^^^^ help: change this to: `&str` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do --> tests/ui/ptr_arg.rs:182:21 @@ -143,8 +143,8 @@ help: change this to LL ~ fn foo_vec(vec: &[u8]) { LL | LL | -LL ~ let _ = vec.to_owned().pop(); -LL ~ let _ = vec.to_owned().clone(); +LL ~ let a = vec.to_owned().pop(); +LL ~ let b = vec.to_owned().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do @@ -158,23 +158,23 @@ help: change this to LL ~ fn foo_path(path: &Path) { LL | LL | -LL ~ let _ = path.to_path_buf().pop(); -LL ~ let _ = path.to_path_buf().clone(); +LL ~ let c = path.to_path_buf().pop(); +LL ~ let d = path.to_path_buf().clone(); | -error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do +error: writing `&String` instead of `&str` involves a new object where a slice will do --> tests/ui/ptr_arg.rs:196:21 | -LL | fn foo_str(str: &PathBuf) { - | ^^^^^^^^ +LL | fn foo_str(str: &String) { + | ^^^^^^^ | help: change this to | -LL ~ fn foo_str(str: &Path) { +LL ~ fn foo_str(str: &str) { LL | LL | -LL ~ let _ = str.to_path_buf().pop(); -LL ~ let _ = str.to_path_buf().clone(); +LL ~ let e = str.to_owned().pop(); +LL ~ let f = str.to_owned().clone(); | error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do @@ -231,6 +231,42 @@ error: writing `&String` instead of `&str` involves a new object where a slice w LL | fn good(v1: &String, v2: &String) { | ^^^^^^^ help: change this to: `&str` +error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:363:20 + | +LL | fn foo_used(x: &Vec<i32>) { + | ^^^^^^^^^ help: change this to: `&[i32]` + +error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:377:26 + | +LL | fn foo_local_used(x: &Vec<i32>) { + | ^^^^^^^^^ help: change this to: `&[i32]` + +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:386:33 + | +LL | fn foofoo(_x: &Vec<i32>, y: &String) { + | ^^^^^^^ help: change this to: `&str` + +error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:407:20 + | +LL | fn bar_used(x: &mut Vec<u32>) { + | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` + +error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:421:26 + | +LL | fn bar_local_used(x: &mut Vec<u32>) { + | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` + +error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:430:37 + | +LL | fn barbar(_x: &mut Vec<u32>, y: &mut String) { + | ^^^^^^^^^^^ help: change this to: `&mut str` + error: eliding a lifetime that's named elsewhere is confusing --> tests/ui/ptr_arg.rs:314:36 | @@ -248,5 +284,5 @@ help: consistently use `'a` LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str { | ++ -error: aborting due to 27 previous errors +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index 2033f31c1ee..71fea6144e7 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -219,3 +219,11 @@ mod null_entire_infer { //~^ ptr_as_ptr } } + +#[allow(clippy::transmute_null_to_fn)] +fn issue15283() { + unsafe { + let _: fn() = std::mem::transmute(std::ptr::null::<u8>()); + //~^ ptr_as_ptr + } +} diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index 224d09b0eb6..4d507592a1e 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -219,3 +219,11 @@ mod null_entire_infer { //~^ ptr_as_ptr } } + +#[allow(clippy::transmute_null_to_fn)] +fn issue15283() { + unsafe { + let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); + //~^ ptr_as_ptr + } +} diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index 66dae8e0135..adad159bb0f 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -201,5 +201,11 @@ error: `as` casting between raw pointers without changing their constness LL | core::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` -error: aborting due to 33 previous errors +error: `as` casting between raw pointers without changing their constness + --> tests/ui/ptr_as_ptr.rs:226:43 + | +LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u8>()` + +error: aborting due to 34 previous errors diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed index ee716ef3a6a..5c6da6d5aed 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed @@ -1,5 +1,9 @@ +#![warn(clippy::range_minus_one, clippy::range_plus_one)] #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] + +use std::ops::{Index, IndexMut, Range, RangeBounds, RangeInclusive}; + fn f() -> usize { 42 } @@ -20,8 +24,6 @@ macro_rules! macro_minus_one { }; } -#[warn(clippy::range_plus_one)] -#[warn(clippy::range_minus_one)] fn main() { for _ in 0..2 {} for _ in 0..=2 {} @@ -45,15 +47,13 @@ fn main() { //~^ range_plus_one for _ in 0..=(1 + f()) {} + // Those are not linted, as in the general case we cannot be sure that the exact type won't be + // important. let _ = ..11 - 1; - let _ = ..11; - //~^ range_minus_one - let _ = ..11; - //~^ range_minus_one - let _ = (1..=11); - //~^ range_plus_one - let _ = ((f() + 1)..=f()); - //~^ range_plus_one + let _ = ..=11 - 1; + let _ = ..=(11 - 1); + let _ = (1..11 + 1); + let _ = (f() + 1)..(f() + 1); const ONE: usize = 1; // integer consts are linted, too @@ -65,4 +65,118 @@ fn main() { macro_plus_one!(5); macro_minus_one!(5); + + // As an instance of `Iterator` + (1..=10).for_each(|_| {}); + //~^ range_plus_one + + // As an instance of `IntoIterator` + #[allow(clippy::useless_conversion)] + (1..=10).into_iter().for_each(|_| {}); + //~^ range_plus_one + + // As an instance of `RangeBounds` + { + let _ = (1..=10).start_bound(); + //~^ range_plus_one + } + + // As a `SliceIndex` + let a = [10, 20, 30]; + let _ = &a[1..=1]; + //~^ range_plus_one + + // As method call argument + vec.drain(2..=3); + //~^ range_plus_one + + // As function call argument + take_arg(10..=20); + //~^ range_plus_one + + // As function call argument inside a block + take_arg({ 10..=20 }); + //~^ range_plus_one + + // Do not lint in case types are unified + take_arg(if true { 10..20 } else { 10..20 + 1 }); + + // Do not lint, as the same type is used for both parameters + take_args(10..20 + 1, 10..21); + + // Do not lint, as the range type is also used indirectly in second parameter + take_arg_and_struct(10..20 + 1, S { t: 1..2 }); + + // As target of `IndexMut` + let mut a = [10, 20, 30]; + a[0..=2][0] = 1; + //~^ range_plus_one +} + +fn take_arg<T: Iterator<Item = u32>>(_: T) {} +fn take_args<T: Iterator<Item = u32>>(_: T, _: T) {} + +struct S<T> { + t: T, +} +fn take_arg_and_struct<T: Iterator<Item = u32>>(_: T, _: S<T>) {} + +fn no_index_by_range_inclusive(a: usize) { + struct S; + + impl Index<Range<usize>> for S { + type Output = [u32]; + fn index(&self, _: Range<usize>) -> &Self::Output { + &[] + } + } + + _ = &S[0..a + 1]; +} + +fn no_index_mut_with_switched_range(a: usize) { + struct S(u32); + + impl Index<Range<usize>> for S { + type Output = u32; + fn index(&self, _: Range<usize>) -> &Self::Output { + &self.0 + } + } + + impl IndexMut<Range<usize>> for S { + fn index_mut(&mut self, _: Range<usize>) -> &mut Self::Output { + &mut self.0 + } + } + + impl Index<RangeInclusive<usize>> for S { + type Output = u32; + fn index(&self, _: RangeInclusive<usize>) -> &Self::Output { + &self.0 + } + } + + S(2)[0..a + 1] = 3; +} + +fn issue9908() { + // Simplified test case + let _ = || 0..=1; + + // Original test case + let full_length = 1024; + let range = { + // do some stuff, omit here + None + }; + + let range = range.map(|(s, t)| s..=t).unwrap_or(0..=(full_length - 1)); + + assert_eq!(range, 0..=1023); +} + +fn issue9908_2(n: usize) -> usize { + (1..n).sum() + //~^ range_minus_one } diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.rs b/src/tools/clippy/tests/ui/range_plus_minus_one.rs index f2d5ae2c150..7172da6034b 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.rs +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.rs @@ -1,5 +1,9 @@ +#![warn(clippy::range_minus_one, clippy::range_plus_one)] #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] + +use std::ops::{Index, IndexMut, Range, RangeBounds, RangeInclusive}; + fn f() -> usize { 42 } @@ -20,8 +24,6 @@ macro_rules! macro_minus_one { }; } -#[warn(clippy::range_plus_one)] -#[warn(clippy::range_minus_one)] fn main() { for _ in 0..2 {} for _ in 0..=2 {} @@ -45,15 +47,13 @@ fn main() { //~^ range_plus_one for _ in 0..=(1 + f()) {} + // Those are not linted, as in the general case we cannot be sure that the exact type won't be + // important. let _ = ..11 - 1; let _ = ..=11 - 1; - //~^ range_minus_one let _ = ..=(11 - 1); - //~^ range_minus_one let _ = (1..11 + 1); - //~^ range_plus_one let _ = (f() + 1)..(f() + 1); - //~^ range_plus_one const ONE: usize = 1; // integer consts are linted, too @@ -65,4 +65,118 @@ fn main() { macro_plus_one!(5); macro_minus_one!(5); + + // As an instance of `Iterator` + (1..10 + 1).for_each(|_| {}); + //~^ range_plus_one + + // As an instance of `IntoIterator` + #[allow(clippy::useless_conversion)] + (1..10 + 1).into_iter().for_each(|_| {}); + //~^ range_plus_one + + // As an instance of `RangeBounds` + { + let _ = (1..10 + 1).start_bound(); + //~^ range_plus_one + } + + // As a `SliceIndex` + let a = [10, 20, 30]; + let _ = &a[1..1 + 1]; + //~^ range_plus_one + + // As method call argument + vec.drain(2..3 + 1); + //~^ range_plus_one + + // As function call argument + take_arg(10..20 + 1); + //~^ range_plus_one + + // As function call argument inside a block + take_arg({ 10..20 + 1 }); + //~^ range_plus_one + + // Do not lint in case types are unified + take_arg(if true { 10..20 } else { 10..20 + 1 }); + + // Do not lint, as the same type is used for both parameters + take_args(10..20 + 1, 10..21); + + // Do not lint, as the range type is also used indirectly in second parameter + take_arg_and_struct(10..20 + 1, S { t: 1..2 }); + + // As target of `IndexMut` + let mut a = [10, 20, 30]; + a[0..2 + 1][0] = 1; + //~^ range_plus_one +} + +fn take_arg<T: Iterator<Item = u32>>(_: T) {} +fn take_args<T: Iterator<Item = u32>>(_: T, _: T) {} + +struct S<T> { + t: T, +} +fn take_arg_and_struct<T: Iterator<Item = u32>>(_: T, _: S<T>) {} + +fn no_index_by_range_inclusive(a: usize) { + struct S; + + impl Index<Range<usize>> for S { + type Output = [u32]; + fn index(&self, _: Range<usize>) -> &Self::Output { + &[] + } + } + + _ = &S[0..a + 1]; +} + +fn no_index_mut_with_switched_range(a: usize) { + struct S(u32); + + impl Index<Range<usize>> for S { + type Output = u32; + fn index(&self, _: Range<usize>) -> &Self::Output { + &self.0 + } + } + + impl IndexMut<Range<usize>> for S { + fn index_mut(&mut self, _: Range<usize>) -> &mut Self::Output { + &mut self.0 + } + } + + impl Index<RangeInclusive<usize>> for S { + type Output = u32; + fn index(&self, _: RangeInclusive<usize>) -> &Self::Output { + &self.0 + } + } + + S(2)[0..a + 1] = 3; +} + +fn issue9908() { + // Simplified test case + let _ = || 0..=1; + + // Original test case + let full_length = 1024; + let range = { + // do some stuff, omit here + None + }; + + let range = range.map(|(s, t)| s..=t).unwrap_or(0..=(full_length - 1)); + + assert_eq!(range, 0..=1023); +} + +fn issue9908_2(n: usize) -> usize { + (1..=n - 1).sum() + //~^ range_minus_one } diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr index 9b23a8b8c0b..a419d935bd6 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr @@ -1,5 +1,5 @@ error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:29:14 + --> tests/ui/range_plus_minus_one.rs:31:14 | LL | for _ in 0..3 + 1 {} | ^^^^^^^^ help: use: `0..=3` @@ -8,55 +8,85 @@ LL | for _ in 0..3 + 1 {} = help: to override `-D warnings` add `#[allow(clippy::range_plus_one)]` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:33:14 + --> tests/ui/range_plus_minus_one.rs:35:14 | LL | for _ in 0..1 + 5 {} | ^^^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:37:14 + --> tests/ui/range_plus_minus_one.rs:39:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:44:14 + --> tests/ui/range_plus_minus_one.rs:46:14 | LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` -error: an exclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:49:13 +error: an inclusive range would be more readable + --> tests/ui/range_plus_minus_one.rs:60:14 | -LL | let _ = ..=11 - 1; - | ^^^^^^^^^ help: use: `..11` +LL | for _ in 1..ONE + ONE {} + | ^^^^^^^^^^^^ help: use: `1..=ONE` + +error: an inclusive range would be more readable + --> tests/ui/range_plus_minus_one.rs:70:5 | - = note: `-D clippy::range-minus-one` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]` +LL | (1..10 + 1).for_each(|_| {}); + | ^^^^^^^^^^^ help: use: `(1..=10)` -error: an exclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:51:13 +error: an inclusive range would be more readable + --> tests/ui/range_plus_minus_one.rs:75:5 | -LL | let _ = ..=(11 - 1); - | ^^^^^^^^^^^ help: use: `..11` +LL | (1..10 + 1).into_iter().for_each(|_| {}); + | ^^^^^^^^^^^ help: use: `(1..=10)` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:53:13 + --> tests/ui/range_plus_minus_one.rs:80:17 | -LL | let _ = (1..11 + 1); - | ^^^^^^^^^^^ help: use: `(1..=11)` +LL | let _ = (1..10 + 1).start_bound(); + | ^^^^^^^^^^^ help: use: `(1..=10)` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:55:13 + --> tests/ui/range_plus_minus_one.rs:86:16 | -LL | let _ = (f() + 1)..(f() + 1); - | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())` +LL | let _ = &a[1..1 + 1]; + | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:60:14 + --> tests/ui/range_plus_minus_one.rs:90:15 | -LL | for _ in 1..ONE + ONE {} - | ^^^^^^^^^^^^ help: use: `1..=ONE` +LL | vec.drain(2..3 + 1); + | ^^^^^^^^ help: use: `2..=3` + +error: an inclusive range would be more readable + --> tests/ui/range_plus_minus_one.rs:94:14 + | +LL | take_arg(10..20 + 1); + | ^^^^^^^^^^ help: use: `10..=20` + +error: an inclusive range would be more readable + --> tests/ui/range_plus_minus_one.rs:98:16 + | +LL | take_arg({ 10..20 + 1 }); + | ^^^^^^^^^^ help: use: `10..=20` + +error: an inclusive range would be more readable + --> tests/ui/range_plus_minus_one.rs:112:7 + | +LL | a[0..2 + 1][0] = 1; + | ^^^^^^^^ help: use: `0..=2` + +error: an exclusive range would be more readable + --> tests/ui/range_plus_minus_one.rs:180:5 + | +LL | (1..=n - 1).sum() + | ^^^^^^^^^^^ help: use: `(1..n)` + | + = note: `-D clippy::range-minus-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]` -error: aborting due to 9 previous errors +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/single_match_else_deref_patterns.fixed b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.fixed new file mode 100644 index 00000000000..7a9f8063096 --- /dev/null +++ b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.fixed @@ -0,0 +1,53 @@ +#![feature(deref_patterns)] +#![allow( + incomplete_features, + clippy::eq_op, + clippy::op_ref, + clippy::deref_addrof, + clippy::borrow_deref_ref, + clippy::needless_if +)] +#![deny(clippy::single_match_else)] + +fn string() { + if *"" == *"" {} + + if *&*&*&*"" == *"" {} + + if ***&&"" == *"" {} + + if *&*&*"" == *"" {} + + if **&&*"" == *"" {} +} + +fn int() { + if &&&1 == &&&2 { unreachable!() } else { + // ok + } + //~^^^^^^ single_match_else + if &&1 == &&2 { unreachable!() } else { + // ok + } + //~^^^^^^ single_match_else + if &&1 == &&2 { unreachable!() } else { + // ok + } + //~^^^^^^ single_match_else + if &1 == &2 { unreachable!() } else { + // ok + } + //~^^^^^^ single_match_else + if &1 == &2 { unreachable!() } else { + // ok + } + //~^^^^^^ single_match_else + if 1 == 2 { unreachable!() } else { + // ok + } + //~^^^^^^ single_match_else + if 1 == 2 { unreachable!() } else { + // ok + } + //~^^^^^^ single_match_else +} diff --git a/src/tools/clippy/tests/ui/single_match_else_deref_patterns.rs b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.rs new file mode 100644 index 00000000000..ef19c7cbde2 --- /dev/null +++ b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.rs @@ -0,0 +1,94 @@ +#![feature(deref_patterns)] +#![allow( + incomplete_features, + clippy::eq_op, + clippy::op_ref, + clippy::deref_addrof, + clippy::borrow_deref_ref, + clippy::needless_if +)] +#![deny(clippy::single_match_else)] + +fn string() { + match *"" { + //~^ single_match + "" => {}, + _ => {}, + } + + match *&*&*&*"" { + //~^ single_match + "" => {}, + _ => {}, + } + + match ***&&"" { + //~^ single_match + "" => {}, + _ => {}, + } + + match *&*&*"" { + //~^ single_match + "" => {}, + _ => {}, + } + + match **&&*"" { + //~^ single_match + "" => {}, + _ => {}, + } +} + +fn int() { + match &&&1 { + &&&2 => unreachable!(), + _ => { + // ok + }, + } + //~^^^^^^ single_match_else + match &&&1 { + &&2 => unreachable!(), + _ => { + // ok + }, + } + //~^^^^^^ single_match_else + match &&1 { + &&2 => unreachable!(), + _ => { + // ok + }, + } + //~^^^^^^ single_match_else + match &&&1 { + &2 => unreachable!(), + _ => { + // ok + }, + } + //~^^^^^^ single_match_else + match &&1 { + &2 => unreachable!(), + _ => { + // ok + }, + } + //~^^^^^^ single_match_else + match &&&1 { + 2 => unreachable!(), + _ => { + // ok + }, + } + //~^^^^^^ single_match_else + match &&1 { + 2 => unreachable!(), + _ => { + // ok + }, + } + //~^^^^^^ single_match_else +} diff --git a/src/tools/clippy/tests/ui/single_match_else_deref_patterns.stderr b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.stderr new file mode 100644 index 00000000000..a47df55459b --- /dev/null +++ b/src/tools/clippy/tests/ui/single_match_else_deref_patterns.stderr @@ -0,0 +1,188 @@ +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:13:5 + | +LL | / match *"" { +LL | | +LL | | "" => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: try: `if *"" == *"" {}` + | + = note: you might want to preserve the comments from inside the `match` + = note: `-D clippy::single-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_match)]` + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:19:5 + | +LL | / match *&*&*&*"" { +LL | | +LL | | "" => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: try: `if *&*&*&*"" == *"" {}` + | + = note: you might want to preserve the comments from inside the `match` + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:25:5 + | +LL | / match ***&&"" { +LL | | +LL | | "" => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: try: `if ***&&"" == *"" {}` + | + = note: you might want to preserve the comments from inside the `match` + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:31:5 + | +LL | / match *&*&*"" { +LL | | +LL | | "" => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: try: `if *&*&*"" == *"" {}` + | + = note: you might want to preserve the comments from inside the `match` + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:37:5 + | +LL | / match **&&*"" { +LL | | +LL | | "" => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: try: `if **&&*"" == *"" {}` + | + = note: you might want to preserve the comments from inside the `match` + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:45:5 + | +LL | / match &&&1 { +LL | | &&&2 => unreachable!(), +LL | | _ => { +... | +LL | | } + | |_____^ + | +note: the lint level is defined here + --> tests/ui/single_match_else_deref_patterns.rs:10:9 + | +LL | #![deny(clippy::single_match_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try + | +LL ~ if &&&1 == &&&2 { unreachable!() } else { +LL + // ok +LL + } + | + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:52:5 + | +LL | / match &&&1 { +LL | | &&2 => unreachable!(), +LL | | _ => { +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ if &&1 == &&2 { unreachable!() } else { +LL + // ok +LL + } + | + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:59:5 + | +LL | / match &&1 { +LL | | &&2 => unreachable!(), +LL | | _ => { +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ if &&1 == &&2 { unreachable!() } else { +LL + // ok +LL + } + | + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:66:5 + | +LL | / match &&&1 { +LL | | &2 => unreachable!(), +LL | | _ => { +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ if &1 == &2 { unreachable!() } else { +LL + // ok +LL + } + | + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:73:5 + | +LL | / match &&1 { +LL | | &2 => unreachable!(), +LL | | _ => { +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ if &1 == &2 { unreachable!() } else { +LL + // ok +LL + } + | + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:80:5 + | +LL | / match &&&1 { +LL | | 2 => unreachable!(), +LL | | _ => { +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ if 1 == 2 { unreachable!() } else { +LL + // ok +LL + } + | + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match_else_deref_patterns.rs:87:5 + | +LL | / match &&1 { +LL | | 2 => unreachable!(), +LL | | _ => { +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ if 1 == 2 { unreachable!() } else { +LL + // ok +LL + } + | + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs index 14371bc203b..d0022f3b6d9 100644 --- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs +++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs @@ -82,3 +82,32 @@ impl H { } fn main() {} + +mod issue15120 { + macro_rules! uns { + ($e:expr) => { + unsafe { $e } + }; + } + + #[derive(serde::Deserialize)] + struct Foo; + + impl Foo { + fn foo(&self) { + // Do not lint if `unsafe` comes from the `core::pin::pin!()` macro + std::pin::pin!(()); + } + } + + //~v unsafe_derive_deserialize + #[derive(serde::Deserialize)] + struct Bar; + + impl Bar { + fn bar(&self) { + // Lint if `unsafe` comes from the another macro + _ = uns!(42); + } + } +} diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr index f2d4429f707..4b5dd6e61fc 100644 --- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr +++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr @@ -36,5 +36,14 @@ LL | #[derive(Deserialize)] = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` + --> tests/ui/unsafe_derive_deserialize.rs:104:14 + | +LL | #[derive(serde::Deserialize)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html + = note: this error originates in the derive macro `serde::Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs index 433459253dd..7a0be825a2d 100644 --- a/src/tools/clippy/tests/ui/unused_async.rs +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -127,3 +127,13 @@ mod issue14704 { async fn cancel(self: Arc<Self>) {} } } + +mod issue15305 { + async fn todo_task() -> Result<(), String> { + todo!("Implement task"); + } + + async fn unimplemented_task() -> Result<(), String> { + unimplemented!("Implement task"); + } +} diff --git a/src/tools/clippy/tests/ui/unused_trait_names.fixed b/src/tools/clippy/tests/ui/unused_trait_names.fixed index 17e32ddfd9d..6abbed01bb0 100644 --- a/src/tools/clippy/tests/ui/unused_trait_names.fixed +++ b/src/tools/clippy/tests/ui/unused_trait_names.fixed @@ -200,11 +200,11 @@ fn msrv_1_33() { MyStruct.do_things(); } +// Linting inside macro expansion is no longer supported mod lint_inside_macro_expansion_bad { macro_rules! foo { () => { - use std::any::Any as _; - //~^ unused_trait_names + use std::any::Any; fn bar() { "bar".type_id(); } diff --git a/src/tools/clippy/tests/ui/unused_trait_names.rs b/src/tools/clippy/tests/ui/unused_trait_names.rs index 3cf8597e535..4a06f062dc3 100644 --- a/src/tools/clippy/tests/ui/unused_trait_names.rs +++ b/src/tools/clippy/tests/ui/unused_trait_names.rs @@ -200,11 +200,11 @@ fn msrv_1_33() { MyStruct.do_things(); } +// Linting inside macro expansion is no longer supported mod lint_inside_macro_expansion_bad { macro_rules! foo { () => { use std::any::Any; - //~^ unused_trait_names fn bar() { "bar".type_id(); } diff --git a/src/tools/clippy/tests/ui/unused_trait_names.stderr b/src/tools/clippy/tests/ui/unused_trait_names.stderr index 3183289d853..28067e17414 100644 --- a/src/tools/clippy/tests/ui/unused_trait_names.stderr +++ b/src/tools/clippy/tests/ui/unused_trait_names.stderr @@ -58,16 +58,5 @@ error: importing trait that is only used anonymously LL | use simple_trait::{MyStruct, MyTrait}; | ^^^^^^^ help: use: `MyTrait as _` -error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:206:27 - | -LL | use std::any::Any; - | ^^^ help: use: `Any as _` -... -LL | foo!(); - | ------ in this macro invocation - | - = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/used_underscore_items.rs b/src/tools/clippy/tests/ui/used_underscore_items.rs index 7e8289f1406..aecdd32693c 100644 --- a/src/tools/clippy/tests/ui/used_underscore_items.rs +++ b/src/tools/clippy/tests/ui/used_underscore_items.rs @@ -62,13 +62,13 @@ fn main() { //~^ used_underscore_items } -// should not lint exteranl crate. +// should not lint external crate. // user cannot control how others name their items fn external_item_call() { let foo_struct3 = external_item::_ExternalStruct {}; foo_struct3._foo(); - external_item::_exernal_foo(); + external_item::_external_foo(); } // should not lint foreign functions. diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed index 930bc1eaecf..be4fb55ddfb 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.fixed +++ b/src/tools/clippy/tests/ui/useless_attribute.fixed @@ -146,3 +146,15 @@ pub mod unknown_namespace { #[allow(rustc::non_glob_import_of_type_ir_inherent)] use some_module::SomeType; } + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/15316 +pub mod redundant_imports_issue { + macro_rules! empty { + () => {}; + } + + #[expect(redundant_imports)] + pub(crate) use empty; + + empty!(); +} diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs index 50fafd478e5..5a1bcf97a5b 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.rs +++ b/src/tools/clippy/tests/ui/useless_attribute.rs @@ -146,3 +146,15 @@ pub mod unknown_namespace { #[allow(rustc::non_glob_import_of_type_ir_inherent)] use some_module::SomeType; } + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/15316 +pub mod redundant_imports_issue { + macro_rules! empty { + () => {}; + } + + #[expect(redundant_imports)] + pub(crate) use empty; + + empty!(); +} diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 805baf2af6d..a62b6269a3b 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -54,6 +54,7 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB users_on_vacation = [ "matthiaskrgr", "Manishearth", + "samueltardieu", ] [assign.owners] diff --git a/src/tools/clippy/util/gh-pages/index_template.html b/src/tools/clippy/util/gh-pages/index_template.html index 6f380ec8fee..5d65ea585df 100644 --- a/src/tools/clippy/util/gh-pages/index_template.html +++ b/src/tools/clippy/util/gh-pages/index_template.html @@ -49,9 +49,7 @@ Otherwise, have a great day =^.^= <script src="theme.js"></script> {# #} <div class="container"> {# #} - <div class="page-header"> {# #} - <h1>Clippy Lints <span id="lint-count" class="badge"></span></h1> {# #} - </div> {# #} + <h1 class="page-header">Clippy Lints <span id="lint-count" class="badge"></span></h1> {# #} <noscript> {# #} <div class="alert alert-danger" role="alert"> {# #} @@ -59,143 +57,141 @@ Otherwise, have a great day =^.^= </div> {# #} </noscript> {# #} - <div> {# #} - <div class="panel panel-default" id="menu-filters"> {# #} - <div class="panel-body row"> {# #} - <div id="upper-filters" class="col-12 col-md-5"> {# #} - <div class="btn-group" id="lint-levels" tabindex="-1"> {# #} - <button type="button" class="btn btn-default dropdown-toggle"> {# #} - Lint levels <span class="badge">4</span> <span class="caret"></span> {# #} - </button> {# #} - <ul class="dropdown-menu" id="lint-levels-selector"> {# #} - <li class="checkbox"> {# #} - <button onclick="toggleElements('levels_filter', true)">All</button> {# #} - </li> {# #} - <li class="checkbox"> {# #} - <button onclick="toggleElements('levels_filter', false)">None</button> {# #} - </li> {# #} - <li role="separator" class="divider"></li> {# #} - </ul> {# #} - </div> {# #} - <div class="btn-group" id="lint-groups" tabindex="-1"> {# #} - <button type="button" class="btn btn-default dropdown-toggle"> {# #} - Lint groups <span class="badge">9</span> <span class="caret"></span> {# #} - </button> {# #} - <ul class="dropdown-menu" id="lint-groups-selector"> {# #} - <li class="checkbox"> {# #} - <button onclick="toggleElements('groups_filter', true)">All</button> {# #} - </li> {# #} - <li class="checkbox"> {# #} - <button onclick="resetGroupsToDefault()">Default</button> {# #} - </li> {# #} - <li class="checkbox"> {# #} - <button onclick="toggleElements('groups_filter', false)">None</button> {# #} - </li> {# #} - <li role="separator" class="divider"></li> {# #} - </ul> {# #} - </div> {# #} - <div class="btn-group" id="version-filter" tabindex="-1"> {# #} - <button type="button" class="btn btn-default dropdown-toggle"> {# #} - Version {#+ #} - <span id="version-filter-count" class="badge">0</span> {#+ #} - <span class="caret"></span> {# #} - </button> {# #} - <ul id="version-filter-selector" class="dropdown-menu"> {# #} - <li class="checkbox"> {# #} - <button onclick="clearVersionFilters()">Clear filters</button> {# #} - </li> {# #} - <li role="separator" class="divider"></li> {# #} - </ul> {# #} - </div> {# #} - <div class="btn-group" id="lint-applicabilities" tabindex="-1"> {# #} - <button type="button" class="btn btn-default dropdown-toggle"> {# #} - Applicability {#+ #} - <span class="badge">4</span> {#+ #} - <span class="caret"></span> {# #} - </button> {# #} - <ul class="dropdown-menu" id="lint-applicabilities-selector"> {# #} - <li class="checkbox"> {# #} - <button onclick="toggleElements('applicabilities_filter', true)">All</button> {# #} - </li> {# #} - <li class="checkbox"> {# #} - <button onclick="toggleElements('applicabilities_filter', false)">None</button> {# #} - </li> {# #} - <li role="separator" class="divider"></li> {# #} - </ul> {# #} - </div> {# #} + <div id="menu-filters"> {# #} + <div class="panel-body row"> {# #} + <div id="upper-filters" class="col-12 col-md-5"> {# #} + <div class="btn-group" id="lint-levels" tabindex="-1"> {# #} + <button type="button" class="btn btn-default dropdown-toggle"> {# #} + Lint levels <span class="badge">4</span> <span class="caret"></span> {# #} + </button> {# #} + <ul class="dropdown-menu" id="lint-levels-selector"> {# #} + <li class="checkbox"> {# #} + <button onclick="toggleElements('levels_filter', true)">All</button> {# #} + </li> {# #} + <li class="checkbox"> {# #} + <button onclick="toggleElements('levels_filter', false)">None</button> {# #} + </li> {# #} + <li role="separator" class="divider"></li> {# #} + </ul> {# #} </div> {# #} - <div class="col-12 col-md-5 search-control"> {# #} - <div class="input-group"> {# #} - <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label> {# #} - <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input" /> {# #} - <span class="input-group-btn"> {# #} - <button class="filter-clear btn" type="button" onclick="searchState.clearInput(event)"> {# #} - Clear {# #} - </button> {# #} - </span> {# #} - </div> {# #} + <div class="btn-group" id="lint-groups" tabindex="-1"> {# #} + <button type="button" class="btn btn-default dropdown-toggle"> {# #} + Lint groups <span class="badge">9</span> <span class="caret"></span> {# #} + </button> {# #} + <ul class="dropdown-menu" id="lint-groups-selector"> {# #} + <li class="checkbox"> {# #} + <button onclick="toggleElements('groups_filter', true)">All</button> {# #} + </li> {# #} + <li class="checkbox"> {# #} + <button onclick="resetGroupsToDefault()">Default</button> {# #} + </li> {# #} + <li class="checkbox"> {# #} + <button onclick="toggleElements('groups_filter', false)">None</button> {# #} + </li> {# #} + <li role="separator" class="divider"></li> {# #} + </ul> {# #} </div> {# #} - <div class="col-12 col-md-2 btn-group expansion-group"> {# #} - <button title="Collapse All" class="btn btn-default expansion-control" type="button" id="collapse-all"> {# #} - <span class="glyphicon glyphicon-collapse-up"></span> {# #} + <div class="btn-group" id="version-filter" tabindex="-1"> {# #} + <button type="button" class="btn btn-default dropdown-toggle"> {# #} + Version {#+ #} + <span id="version-filter-count" class="badge">0</span> {#+ #} + <span class="caret"></span> {# #} </button> {# #} - <button title="Expand All" class="btn btn-default expansion-control" type="button" id="expand-all"> {# #} - <span class="glyphicon glyphicon-collapse-down"></span> {# #} + <ul id="version-filter-selector" class="dropdown-menu"> {# #} + <li class="checkbox"> {# #} + <button onclick="clearVersionFilters()">Clear filters</button> {# #} + </li> {# #} + <li role="separator" class="divider"></li> {# #} + </ul> {# #} + </div> {# #} + <div class="btn-group" id="lint-applicabilities" tabindex="-1"> {# #} + <button type="button" class="btn btn-default dropdown-toggle"> {# #} + Applicability {#+ #} + <span class="badge">4</span> {#+ #} + <span class="caret"></span> {# #} </button> {# #} + <ul class="dropdown-menu" id="lint-applicabilities-selector"> {# #} + <li class="checkbox"> {# #} + <button onclick="toggleElements('applicabilities_filter', true)">All</button> {# #} + </li> {# #} + <li class="checkbox"> {# #} + <button onclick="toggleElements('applicabilities_filter', false)">None</button> {# #} + </li> {# #} + <li role="separator" class="divider"></li> {# #} + </ul> {# #} + </div> {# #} + </div> {# #} + <div class="col-12 col-md-5 search-control"> {# #} + <div class="input-group"> {# #} + <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label> {# #} + <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input" /> {# #} + <span class="input-group-btn"> {# #} + <button class="filter-clear btn" type="button" onclick="searchState.clearInput(event)"> {# #} + Clear {# #} + </button> {# #} + </span> {# #} </div> {# #} </div> {# #} - </div> - {% for lint in lints %} - <article class="panel panel-default" id="{{lint.id}}"> {# #} - <input id="label-{{lint.id}}" type="checkbox"> {# #} - <label for="label-{{lint.id}}"> {# #} - <h2 class="lint-title"> {# #} - <div class="panel-title-name" id="lint-{{lint.id}}"> {# #} - {{lint.id +}} - <a href="#{{lint.id}}" class="anchor label label-default">¶</a> {#+ #} - <a href="" class="copy-to-clipboard anchor label label-default"> {# #} - 📋 {# #} - </a> {# #} - </div> {# #} + <div class="col-12 col-md-2 btn-group expansion-group"> {# #} + <button title="Collapse All" class="btn btn-default expansion-control" type="button" id="collapse-all"> {# #} + <span class="glyphicon glyphicon-collapse-up"></span> {# #} + </button> {# #} + <button title="Expand All" class="btn btn-default expansion-control" type="button" id="expand-all"> {# #} + <span class="glyphicon glyphicon-collapse-down"></span> {# #} + </button> {# #} + </div> {# #} + </div> {# #} + </div> + {% for lint in lints %} + <article id="{{lint.id}}"> {# #} + <input id="label-{{lint.id}}" type="checkbox"> {# #} + <label for="label-{{lint.id}}"> {# #} + <h2 class="lint-title"> {# #} + <div class="panel-title-name" id="lint-{{lint.id}}"> {# #} + {{lint.id ~}} + <a href="#{{lint.id}}" class="anchor label label-default">¶</a> {#+ #} + <a href="" class="copy-to-clipboard anchor label label-default"> {# #} + 📋 {# #} + </a> {# #} + </div> {# #} - <span class="label label-lint-group label-default label-group-{{lint.group}}">{{lint.group}}</span> {#+ #} + <span class="label label-default lint-group group-{{lint.group}}">{{lint.group}}</span> {#+ #} - <span class="label label-lint-level label-lint-level-{{lint.level}}">{{lint.level}}</span> {#+ #} + <span class="label lint-level level-{{lint.level}}">{{lint.level}}</span> {#+ #} - <span class="label label-doc-folding"></span> {# #} - </h2> {# #} - </label> {# #} + <span class="label doc-folding"></span> {# #} + </h2> {# #} + </label> {# #} - <div class="list-group lint-docs"> {# #} - <div class="list-group-item lint-doc-md">{{Self::markdown(lint.docs)}}</div> {# #} - <div class="lint-additional-info-container"> - {# Applicability #} - <div> {# #} - Applicability: {#+ #} - <span class="label label-default label-applicability">{{ lint.applicability_str() }}</span> {# #} - <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a> {# #} - </div> - {# Clippy version #} - <div> {# #} - {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {#+ #} - <span class="label label-default label-version">{{lint.version}}</span> {# #} - </div> - {# Open related issues #} + <div class="lint-docs"> {# #} + <div class="lint-doc-md">{{Self::markdown(lint.docs)}}</div> {# #} + <div class="lint-additional-info"> + {# Applicability #} + <div> {# #} + Applicability: {#+ #} + <span class="label label-default applicability">{{ lint.applicability_str() }}</span> {# #} + <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a> {# #} + </div> + {# Clippy version #} + <div> {# #} + {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {#+ #} + <span class="label label-default label-version">{{lint.version}}</span> {# #} + </div> + {# Open related issues #} + <div> {# #} + <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a> {# #} + </div> + + {# Jump to source #} + {% if let Some(id_location) = lint.id_location %} <div> {# #} - <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a> {# #} + <a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a> {# #} </div> - - {# Jump to source #} - {% if let Some(id_location) = lint.id_location %} - <div> {# #} - <a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a> {# #} - </div> - {% endif %} - </div> {# #} + {% endif %} </div> {# #} - </article> - {% endfor %} - </div> {# #} + </div> {# #} + </article> + {% endfor %} </div> {# #} <a {#+ #} diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index ee13f1c0cd8..d3204967531 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -208,7 +208,6 @@ const LEVEL_FILTERS_DEFAULT = { allow: true, warn: true, deny: true, - none: true, }; const APPLICABILITIES_FILTER_DEFAULT = { Unspecified: true, @@ -250,10 +249,10 @@ window.filters = { } return { elem: elem, - group: elem.querySelector(".label-lint-group").innerText, - level: elem.querySelector(".label-lint-level").innerText, + group: elem.querySelector(".lint-group").innerText, + level: elem.querySelector(".lint-level").innerText, version: parseInt(version.split(".")[1]), - applicability: elem.querySelector(".label-applicability").innerText, + applicability: elem.querySelector(".applicability").innerText, filteredOut: false, searchFilteredOut: false, }; @@ -594,19 +593,19 @@ disableShortcutsButton.checked = disableShortcuts; addListeners(); highlightLazily(); -generateSettings(); -generateSearch(); -parseURLFilters(); -scrollToLintByURL(); -filters.filterLints(); -updateLintCount(); - function updateLintCount() { const allLints = filters.getAllLints().filter(lint => lint.group != "deprecated"); const totalLints = allLints.length; - + const countElement = document.getElementById("lint-count"); if (countElement) { countElement.innerText = `Total number: ${totalLints}`; } } + +generateSettings(); +generateSearch(); +parseURLFilters(); +scrollToLintByURL(); +filters.filterLints(); +updateLintCount(); diff --git a/src/tools/clippy/util/gh-pages/style.css b/src/tools/clippy/util/gh-pages/style.css index 022ea875200..66abf4598b0 100644 --- a/src/tools/clippy/util/gh-pages/style.css +++ b/src/tools/clippy/util/gh-pages/style.css @@ -30,17 +30,25 @@ blockquote { font-size: 1em; } background-color: var(--theme-hover); } -div.panel div.panel-body button { +.container > * { + margin-bottom: 20px; + border-radius: 4px; + background: var(--bg); + border: 1px solid var(--theme-popup-border); + box-shadow: 0 1px 1px rgba(0,0,0,.05); +} + +div.panel-body button { background: var(--searchbar-bg); color: var(--searchbar-fg); border-color: var(--theme-popup-border); } -div.panel div.panel-body button:hover { +div.panel-body button:hover { box-shadow: 0 0 3px var(--searchbar-shadow-color); } -div.panel div.panel-body button.open { +div.panel-body button.open { filter: brightness(90%); } @@ -48,8 +56,6 @@ div.panel div.panel-body button.open { background-color: #777; } -.panel-heading { cursor: pointer; } - .lint-title { cursor: pointer; margin-top: 0; @@ -70,8 +76,8 @@ div.panel div.panel-body button.open { .panel-title-name { flex: 1; min-width: 400px;} -.panel .panel-title-name .anchor { display: none; } -.panel:hover .panel-title-name .anchor { display: inline;} +.panel-title-name .anchor { display: none; } +article:hover .panel-title-name .anchor { display: inline;} .search-control { margin-top: 15px; @@ -111,40 +117,48 @@ div.panel div.panel-body button.open { padding-bottom: 0.3em; } -.label-lint-group { - min-width: 8em; -} -.label-lint-level { +.lint-level { min-width: 4em; } - -.label-lint-level-allow { +.level-allow { background-color: #5cb85c; } -.label-lint-level-warn { +.level-warn { background-color: #f0ad4e; } -.label-lint-level-deny { +.level-deny { background-color: #d9534f; } -.label-lint-level-none { +.level-none { background-color: #777777; opacity: 0.5; } -.label-group-deprecated { +.lint-group { + min-width: 8em; +} +.group-deprecated { opacity: 0.5; } -.label-doc-folding { +.doc-folding { color: #000; background-color: #fff; border: 1px solid var(--theme-popup-border); } -.label-doc-folding:hover { +.doc-folding:hover { background-color: #e6e6e6; } +.lint-doc-md { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background: 0%; + border-bottom: 1px solid var(--theme-popup-border); + border-top: 1px solid var(--theme-popup-border); +} .lint-doc-md > h3 { border-top: 1px solid var(--theme-popup-border); padding: 10px 15px; @@ -157,32 +171,32 @@ div.panel div.panel-body button.open { } @media (max-width:749px) { - .lint-additional-info-container { + .lint-additional-info { display: flex; flex-flow: column; } - .lint-additional-info-container > div + div { + .lint-additional-info > div + div { border-top: 1px solid var(--theme-popup-border); } } @media (min-width:750px) { - .lint-additional-info-container { + .lint-additional-info { display: flex; flex-flow: row; } - .lint-additional-info-container > div + div { + .lint-additional-info > div + div { border-left: 1px solid var(--theme-popup-border); } } -.lint-additional-info-container > div { +.lint-additional-info > div { display: inline-flex; min-width: 200px; flex-grow: 1; padding: 9px 5px 5px 15px; } -.label-applicability { +.applicability { background-color: #777777; margin: auto 5px; } @@ -332,21 +346,12 @@ L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.649 border: 1px solid var(--theme-popup-border); } .page-header { - border-color: var(--theme-popup-border); -} -.panel-default .panel-heading { - background: var(--theme-hover); - color: var(--fg); - border: 1px solid var(--theme-popup-border); -} -.panel-default .panel-heading:hover { - filter: brightness(90%); -} -.list-group-item { - background: 0%; - border: 1px solid var(--theme-popup-border); + border: 0; + border-bottom: 1px solid var(--theme-popup-border); + padding-bottom: 19px; + border-radius: 0; } -.panel, pre, hr { +pre, hr { background: var(--bg); border: 1px solid var(--theme-popup-border); } @@ -442,14 +447,15 @@ article > label { article > input[type="checkbox"] { display: none; } -article > input[type="checkbox"] + label .label-doc-folding::before { +article > input[type="checkbox"] + label .doc-folding::before { content: "+"; } -article > input[type="checkbox"]:checked + label .label-doc-folding::before { +article > input[type="checkbox"]:checked + label .doc-folding::before { content: "−"; } .lint-docs { display: none; + margin-bottom: 0; } article > input[type="checkbox"]:checked ~ .lint-docs { display: block; diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 1397c87ab07..a1f76a07556 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -861,6 +861,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-openbsd", "ignore-pass", "ignore-powerpc", + "ignore-powerpc64", "ignore-remote", "ignore-riscv64", "ignore-rustc-debug-assertions", @@ -991,6 +992,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-stable", "only-thumb", "only-tvos", + "only-uefi", "only-unix", "only-visionos", "only-wasm32", diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 35f6a9e1644..802a1d63d1f 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -285,6 +285,11 @@ fn parse_cfg_name_directive<'a>( if name == "gdb-version" { outcome = MatchOutcome::External; } + + // Don't error out for ignore-backends,as it is handled elsewhere. + if name == "backends" { + outcome = MatchOutcome::External; + } } ParsedNameDirective { diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index e420a450d42..bcb3165de45 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -9,7 +9,7 @@ description = "Produces a manifest of all the copyrighted materials in the Rust [dependencies] anyhow = "1.0.65" askama = "0.14.0" -cargo_metadata = "0.18.1" +cargo_metadata = "0.21" serde = { version = "1.0.147", features = ["derive"] } serde_json = "1.0.85" thiserror = "1" diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs index 3fae26bda47..87cd85c8def 100644 --- a/src/tools/generate-copyright/src/cargo_metadata.rs +++ b/src/tools/generate-copyright/src/cargo_metadata.rs @@ -92,7 +92,8 @@ pub fn get_metadata( continue; } // otherwise it's an out-of-tree dependency - let package_id = Package { name: package.name, version: package.version.to_string() }; + let package_id = + Package { name: package.name.to_string(), version: package.version.to_string() }; output.insert( package_id, PackageMetadata { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 9ecbd31c5b9..8fdf8d643ea 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -382,7 +382,7 @@ pub fn report_error<'tcx>( helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id)); } } - AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => { + AbiMismatchArgument { .. } => { helps.push(note!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")); helps.push(note!("if you think this code should be accepted anyway, please report an issue with Miri")); } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index ccfff7fa94b..15699828e00 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1079,6 +1079,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .position(|b| !b) { throw_ub!(AbiMismatchArgument { + arg_idx: index, caller_ty: caller_fn_abi.args[index].layout.ty, callee_ty: callee_fn_abi.args[index].layout.ty }); diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs index 4468eb299f3..26f2e73dd75 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs @@ -17,5 +17,5 @@ fn main() { // These two types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::<fn(S), fn(A)>(f) }; - g(Default::default()) //~ ERROR: calling a function with argument of type S passing data of type [i32; 4] + g(Default::default()) //~ ERROR: type S passing argument of type [i32; 4] } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr index cabefa8bee9..f793abb0b62 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type S passing data of type [i32; 4] +error: Undefined Behavior: calling a function whose parameter #1 has type S passing argument of type [i32; 4] --> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC | LL | g(Default::default()) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs index a1fda329e8d..0cca4a13233 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn(f32), fn(i32)>(f) }; - g(42) //~ ERROR: calling a function with argument of type f32 passing data of type i32 + g(42) //~ ERROR: type f32 passing argument of type i32 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr index 52cc48d58ce..3651fc9b3f7 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type f32 passing data of type i32 +error: Undefined Behavior: calling a function whose parameter #1 has type f32 passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC | LL | g(42) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs index f0ea5ccfe0f..053a4a5f284 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn(*const [i32]), fn(*const i32)>(f) }; - g(&42 as *const i32) //~ ERROR: calling a function with argument of type *const [i32] passing data of type *const i32 + g(&42 as *const i32) //~ ERROR: type *const [i32] passing argument of type *const i32 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr index 2fbb0408c59..88345a0688c 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32 +error: Undefined Behavior: calling a function whose parameter #1 has type *const [i32] passing argument of type *const i32 --> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC | LL | g(&42 as *const i32) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs index c5900489b4c..f3dffcc4e86 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs @@ -12,5 +12,5 @@ fn main() { let fnptr: fn(S2) = callee; let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) }; fnptr(S1(NonZero::new(1).unwrap())); - //~^ ERROR: calling a function with argument of type S2 passing data of type S1 + //~^ ERROR: type S2 passing argument of type S1 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr index 2c1ac0ee702..47658395132 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type S2 passing data of type S1 +error: Undefined Behavior: calling a function whose parameter #1 has type S2 passing argument of type S1 --> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC | LL | fnptr(S1(NonZero::new(1).unwrap())); diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs index 0fdab49b94b..05b645cf75a 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs @@ -5,5 +5,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn() -> u32, fn()>(f) }; - g() //~ ERROR: calling a function with return type u32 passing return place of type () + g() //~ ERROR: type u32 passing return place of type () } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr index 28c676ad482..07e6561b53e 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr @@ -6,8 +6,6 @@ LL | g() | = 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 - = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets - = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: = note: inside `main` at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs index 20384f0965b..ca43c06008f 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn((i32, i32)), fn(i32)>(f) }; - g(42) //~ ERROR: calling a function with argument of type (i32, i32) passing data of type i32 + g(42) //~ ERROR: type (i32, i32) passing argument of type i32 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr index e45ad12ec05..2ed9ac2e6da 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32 +error: Undefined Behavior: calling a function whose parameter #1 has type (i32, i32) passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC | LL | g(42) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs index 80f357b61ba..dedcaac6142 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs @@ -7,5 +7,5 @@ fn main() { // These two vector types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::<fn(simd::u32x8), fn(simd::u64x4)>(f) }; - g(Default::default()) //~ ERROR: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4> + g(Default::default()) //~ ERROR: type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4> } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr index bad2495cb39..b13e8d936db 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4> +error: Undefined Behavior: calling a function whose parameter #1 has type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4> --> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC | LL | g(Default::default()) diff --git a/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs b/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs index eb8de04dcc4..77699776aea 100644 --- a/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs +++ b/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs @@ -16,6 +16,6 @@ fn main() { } as u32; let _ = unsafe { close(fd); - //~^ ERROR: calling a function with argument of type i32 passing data of type u32 + //~^ ERROR: type i32 passing argument of type u32 }; } diff --git a/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr b/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr index ce00b624a42..ec27fd5ebb8 100644 --- a/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr +++ b/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 +error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32 --> tests/fail/shims/input_arg_mismatch.rs:LL:CC | LL | close(fd); diff --git a/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr b/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr index 18ff3067fa0..080ee16a2eb 100644 --- a/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr +++ b/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr @@ -6,8 +6,6 @@ LL | close(fd); | = 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 - = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets - = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: = note: inside `main` at tests/fail/shims/return_type_mismatch.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs index 6df132d3255..36bd1e99cfb 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs @@ -6,7 +6,7 @@ fn main() { // the error should point to `become g(x)`, // but tail calls mess up the backtrace it seems like... f(0); - //~^ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 + //~^ error: type i32 passing argument of type u32 } fn f(x: u32) { diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr index fbb0d3d565d..cabea5df85d 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 +error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32 --> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC | LL | f(0); diff --git a/src/tools/miropt-test-tools/Cargo.toml b/src/tools/miropt-test-tools/Cargo.toml index 09b4c7d16dc..3eb5020968d 100644 --- a/src/tools/miropt-test-tools/Cargo.toml +++ b/src/tools/miropt-test-tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "miropt-test-tools" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs index 41b53d2ad0e..10769c9c8ab 100644 --- a/src/tools/miropt-test-tools/src/lib.rs +++ b/src/tools/miropt-test-tools/src/lib.rs @@ -34,7 +34,7 @@ fn output_file_suffix(testfile: &Path, bit_width: u32, panic_strategy: PanicStra let mut suffix = String::new(); if each_bit_width { - suffix.push_str(&format!(".{}bit", bit_width)); + suffix.push_str(&format!(".{bit_width}bit")); } if each_panic_strategy { match panic_strategy { @@ -51,7 +51,7 @@ pub fn files_for_miropt_test( panic_strategy: PanicStrategy, ) -> MiroptTest { let mut out = Vec::new(); - let test_file_contents = fs::read_to_string(&testfile).unwrap(); + let test_file_contents = fs::read_to_string(testfile).unwrap(); let test_dir = testfile.parent().unwrap(); let test_crate = testfile.file_stem().unwrap().to_str().unwrap().replace('-', "_"); @@ -76,10 +76,10 @@ pub fn files_for_miropt_test( if test_name.ends_with(".diff") { let trimmed = test_name.trim_end_matches(".diff"); - passes.push(trimmed.split('.').last().unwrap().to_owned()); - let test_against = format!("{}.after.mir", trimmed); - from_file = format!("{}.before.mir", trimmed); - expected_file = format!("{}{}.diff", trimmed, suffix); + passes.push(trimmed.split('.').next_back().unwrap().to_owned()); + let test_against = format!("{trimmed}.after.mir"); + from_file = format!("{trimmed}.before.mir"); + expected_file = format!("{trimmed}{suffix}.diff"); assert!(test_names.next().is_none(), "two mir pass names specified for MIR diff"); to_file = Some(test_against); } else if let Some(first_pass) = test_names.next() { @@ -92,10 +92,9 @@ pub fn files_for_miropt_test( } assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff"); - expected_file = - format!("{}{}.{}-{}.diff", test_name, suffix, first_pass, second_pass); - let second_file = format!("{}.{}.mir", test_name, second_pass); - from_file = format!("{}.{}.mir", test_name, first_pass); + expected_file = format!("{test_name}{suffix}.{first_pass}-{second_pass}.diff"); + let second_file = format!("{test_name}.{second_pass}.mir"); + from_file = format!("{test_name}.{first_pass}.mir"); to_file = Some(second_file); } else { // Allow-list for file extensions that can be produced by MIR dumps. @@ -112,7 +111,7 @@ pub fn files_for_miropt_test( ) } - expected_file = format!("{}{}.{}", test_name_wo_ext, suffix, test_name_ext); + expected_file = format!("{test_name_wo_ext}{suffix}.{test_name_ext}"); from_file = test_name.to_string(); assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump"); to_file = None; @@ -123,7 +122,7 @@ pub fn files_for_miropt_test( ); }; if !expected_file.starts_with(&test_crate) { - expected_file = format!("{}.{}", test_crate, expected_file); + expected_file = format!("{test_crate}.{expected_file}"); } let expected_file = test_dir.join(expected_file); diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index d995106ae02..c1f27de7ed4 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -6,7 +6,7 @@ autobins = false [dependencies] build_helper = { path = "../../build_helper" } -cargo_metadata = "0.19" +cargo_metadata = "0.21" regex = "1" miropt-test-tools = { path = "../miropt-test-tools" } walkdir = "2" diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index d17ae162ab2..8e2a796106f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -73,7 +73,6 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, // tidy-alphabetical-start ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None, &[]), ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None, &[]), - ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]), ("src/tools/cargo", EXCEPTIONS_CARGO, None, &["src/tools/cargo"]), //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored @@ -81,6 +80,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]), ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]), ("src/tools/test-float-parse", EXCEPTIONS, None, &[]), + ("tests/run-make/uefi-qemu/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]), // tidy-alphabetical-end ]; @@ -135,6 +135,7 @@ const EXCEPTIONS_CARGO: ExceptionList = &[ ("libz-rs-sys", "Zlib"), ("normalize-line-endings", "Apache-2.0"), ("openssl", "Apache-2.0"), + ("ring", "Apache-2.0 AND ISC"), ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 ("similar", "Apache-2.0"), ("sized-chunks", "MPL-2.0+"), @@ -632,8 +633,8 @@ fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, bad: &mut b proc_macro_deps.retain(|pkg| !is_proc_macro_pkg(&metadata[pkg])); let proc_macro_deps: HashSet<_> = - proc_macro_deps.into_iter().map(|dep| metadata[dep].name.clone()).collect(); - let expected = proc_macro_deps::CRATES.iter().map(|s| s.to_string()).collect::<HashSet<_>>(); + proc_macro_deps.into_iter().map(|dep| metadata[dep].name.as_ref()).collect(); + let expected = proc_macro_deps::CRATES.iter().copied().collect::<HashSet<_>>(); let needs_blessing = proc_macro_deps.difference(&expected).next().is_some() || expected.difference(&proc_macro_deps).next().is_some(); @@ -717,7 +718,7 @@ fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) { // See https://github.com/rust-lang/rust/issues/62620 for more. // In general, these should never be added and this exception // should not be taken as precedent for any new target. - if pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") { + if *pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") { continue; } @@ -733,7 +734,7 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba // Validate the EXCEPTIONS list hasn't changed. for (name, license) in exceptions { // Check that the package actually exists. - if !metadata.packages.iter().any(|p| p.name == *name) { + if !metadata.packages.iter().any(|p| *p.name == *name) { tidy_error!( bad, "could not find exception package `{}`\n\ @@ -742,7 +743,7 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba ); } // Check that the license hasn't changed. - for pkg in metadata.packages.iter().filter(|p| p.name == *name) { + for pkg in metadata.packages.iter().filter(|p| *p.name == *name) { match &pkg.license { None => { if *license == NON_STANDARD_LICENSE @@ -817,9 +818,9 @@ fn check_permitted_dependencies( let Ok(version) = Version::parse(version) else { return false; }; - pkg.name == name && pkg.version == version + *pkg.name == name && pkg.version == version } else { - pkg.name == permitted + *pkg.name == permitted } } if !deps.iter().any(|dep_id| compare(pkg_from_id(metadata, dep_id), permitted)) { @@ -867,7 +868,7 @@ fn check_permitted_dependencies( /// Finds a package with the given name. fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package { - let mut i = metadata.packages.iter().filter(|p| p.name == name); + let mut i = metadata.packages.iter().filter(|p| *p.name == name); let result = i.next().unwrap_or_else(|| panic!("could not find package `{name}` in package list")); assert!(i.next().is_none(), "more than one package found for `{name}`"); diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/extra_checks/mod.rs index 8121eb057db..8121eb057db 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs diff --git a/src/tools/tidy/src/ext_tool_checks/rustdoc_js.rs b/src/tools/tidy/src/extra_checks/rustdoc_js.rs index 7708b128e23..7708b128e23 100644 --- a/src/tools/tidy/src/ext_tool_checks/rustdoc_js.rs +++ b/src/tools/tidy/src/extra_checks/rustdoc_js.rs diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 5f6796a9150..4f9fb308a86 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -165,8 +165,8 @@ pub mod debug_artifacts; pub mod deps; pub mod edition; pub mod error_codes; -pub mod ext_tool_checks; pub mod extdeps; +pub mod extra_checks; pub mod features; pub mod filenames; pub mod fluent_alphabetical; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 11ee2ae688d..cd2567ddb64 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -128,9 +128,9 @@ fn main() { check!(pal, &library_path); // Checks that need to be done for both the compiler and std libraries. - check!(unit_tests, &src_path); - check!(unit_tests, &compiler_path); - check!(unit_tests, &library_path); + check!(unit_tests, &src_path, false); + check!(unit_tests, &compiler_path, false); + check!(unit_tests, &library_path, true); if bins::check_filesystem_support(&[&root_path], &output_directory) { check!(bins, &root_path); @@ -177,7 +177,7 @@ fn main() { check!(unstable_book, &src_path, collected); check!( - ext_tool_checks, + extra_checks, &root_path, &output_directory, &ci_info, diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs index df9146b5147..3d14a467319 100644 --- a/src/tools/tidy/src/unit_tests.rs +++ b/src/tools/tidy/src/unit_tests.rs @@ -1,44 +1,60 @@ //! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside -//! `core` or `alloc`. +//! of the standard library. //! //! `core` and `alloc` cannot be tested directly due to duplicating lang items. //! All tests and benchmarks must be written externally in //! `{coretests,alloctests}/{tests,benches}`. //! -//! Outside of `core` and `alloc`, tests and benchmarks should be outlined into -//! separate files named `tests.rs` or `benches.rs`, or directories named +//! Outside of the standard library, tests and benchmarks should be outlined +//! into separate files named `tests.rs` or `benches.rs`, or directories named //! `tests` or `benches` unconfigured during normal build. use std::path::Path; use crate::walk::{filter_dirs, walk}; -pub fn check(root_path: &Path, bad: &mut bool) { - let core = root_path.join("core"); - let core_copy = core.clone(); - let is_core = move |path: &Path| path.starts_with(&core); - let alloc = root_path.join("alloc"); - let alloc_copy = alloc.clone(); - let is_alloc = move |path: &Path| path.starts_with(&alloc); - +pub fn check(root_path: &Path, stdlib: bool, bad: &mut bool) { let skip = move |path: &Path, is_dir| { let file_name = path.file_name().unwrap_or_default(); + + // Skip excluded directories and non-rust files if is_dir { - filter_dirs(path) - || path.ends_with("src/doc") - || (file_name == "tests" || file_name == "benches") - && !is_core(path) - && !is_alloc(path) + if filter_dirs(path) || path.ends_with("src/doc") { + return true; + } } else { let extension = path.extension().unwrap_or_default(); - extension != "rs" - || (file_name == "tests.rs" || file_name == "benches.rs") - && !is_core(path) - && !is_alloc(path) - // Tests which use non-public internals and, as such, need to - // have the types in the same crate as the tests themselves. See - // the comment in alloctests/lib.rs. - || path.ends_with("library/alloc/src/collections/btree/borrow/tests.rs") + if extension != "rs" { + return true; + } + } + + // Tests in a separate package are always allowed + if is_dir && file_name != "tests" && file_name.as_encoded_bytes().ends_with(b"tests") { + return true; + } + + if !stdlib { + // Outside of the standard library tests may also be in separate files in the same crate + if is_dir { + if file_name == "tests" || file_name == "benches" { + return true; + } + } else { + if file_name == "tests.rs" || file_name == "benches.rs" { + return true; + } + } + } + + if is_dir { + // FIXME remove those exceptions once no longer necessary + file_name == "std_detect" || file_name == "std" || file_name == "test" + } else { + // Tests which use non-public internals and, as such, need to + // have the types in the same crate as the tests themselves. See + // the comment in alloctests/lib.rs. + path.ends_with("library/alloc/src/collections/btree/borrow/tests.rs") || path.ends_with("library/alloc/src/collections/btree/map/tests.rs") || path.ends_with("library/alloc/src/collections/btree/node/tests.rs") || path.ends_with("library/alloc/src/collections/btree/set/tests.rs") @@ -50,22 +66,29 @@ pub fn check(root_path: &Path, bad: &mut bool) { walk(root_path, skip, &mut |entry, contents| { let path = entry.path(); - let is_core = path.starts_with(&core_copy); - let is_alloc = path.starts_with(&alloc_copy); + let package = path + .strip_prefix(root_path) + .unwrap() + .components() + .next() + .unwrap() + .as_os_str() + .to_str() + .unwrap(); for (i, line) in contents.lines().enumerate() { let line = line.trim(); let is_test = || line.contains("#[test]") && !line.contains("`#[test]"); let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]"); - let manual_skip = line.contains("//tidy:skip"); - if !line.starts_with("//") && (is_test() || is_bench()) && !manual_skip { - let explanation = if is_core { - "`core` unit tests and benchmarks must be placed into `coretests`" - } else if is_alloc { - "`alloc` unit tests and benchmarks must be placed into `alloctests`" + if !line.starts_with("//") && (is_test() || is_bench()) { + let explanation = if stdlib { + format!( + "`{package}` unit tests and benchmarks must be placed into `{package}tests`" + ) } else { "unit tests and benchmarks must be placed into \ separate files or directories named \ `tests.rs`, `benches.rs`, `tests` or `benches`" + .to_owned() }; let name = if is_test() { "test" } else { "bench" }; tidy_error!( diff --git a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs index 5990fb84942..22599c18dcf 100644 --- a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs +++ b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs @@ -1,7 +1,5 @@ //@ assembly-output: emit-asm //@ compile-flags: -Copt-level=3 -//@ compile-flags: --target aarch64-unknown-linux-gnu -//@ needs-llvm-components: aarch64 //@ only-aarch64 //@ only-linux diff --git a/tests/assembly-llvm/dwarf-mixed-versions-lto.rs b/tests/assembly-llvm/dwarf-mixed-versions-lto.rs index 9910a6e2f5f..828328df843 100644 --- a/tests/assembly-llvm/dwarf-mixed-versions-lto.rs +++ b/tests/assembly-llvm/dwarf-mixed-versions-lto.rs @@ -1,6 +1,7 @@ // This test ensures that if LTO occurs between crates with different DWARF versions, we // will choose the highest DWARF version for the final binary. This matches Clang's behavior. // Note: `.2byte` directive is used on MIPS. +// Note: `.half` directive is used on RISC-V. //@ only-linux //@ aux-build:dwarf-mixed-versions-lto-aux.rs @@ -15,6 +16,6 @@ fn main() { } // CHECK: .section .debug_info -// CHECK-NOT: {{\.(short|hword|2byte)}} 2 -// CHECK-NOT: {{\.(short|hword|2byte)}} 4 -// CHECK: {{\.(short|hword|2byte)}} 5 +// CHECK-NOT: {{\.(short|hword|2byte|half)}} 2 +// CHECK-NOT: {{\.(short|hword|2byte|half)}} 4 +// CHECK: {{\.(short|hword|2byte|half)}} 5 diff --git a/tests/codegen-llvm/cffi/c-variadic-ffi.rs b/tests/codegen-llvm/cffi/c-variadic-ffi.rs new file mode 100644 index 00000000000..3e99c9fb84e --- /dev/null +++ b/tests/codegen-llvm/cffi/c-variadic-ffi.rs @@ -0,0 +1,86 @@ +//! Test calling variadic functions with various ABIs. +//@ add-core-stubs +//@ compile-flags: -Z merge-functions=disabled +//@ revisions: x86_32 x86_32_win x86_64 aarch64 arm32 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] needs-llvm-components: x86 +//@[x86_32_win] compile-flags: --target i686-pc-windows-msvc +//@[x86_32_win] needs-llvm-components: x86 +//@[x86_32] compile-flags: --target i686-unknown-linux-gnu +//@[x86_32] needs-llvm-components: x86 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@[arm32] compile-flags: --target armv7-unknown-linux-gnueabihf +//@[arm32] needs-llvm-components: arm +#![crate_type = "lib"] +#![feature(no_core)] +#![feature(extended_varargs_abi_support, extern_system_varargs)] +#![no_core] + +extern crate minicore; + +// CHECK-LABEL: @c +#[unsafe(no_mangle)] +fn c(f: extern "C" fn(i32, ...)) { + // CHECK: call void (i32, ...) + f(22, 44); +} + +// CHECK-LABEL: @system +#[unsafe(no_mangle)] +fn system(f: extern "system" fn(i32, ...)) { + // Crucially, this is *always* the C calling convention, even on Windows. + // CHECK: call void (i32, ...) + f(22, 44); +} + +// x86_32-LABEL: @cdecl +#[unsafe(no_mangle)] +#[cfg(target_arch = "x86")] +fn cdecl(f: extern "cdecl" fn(i32, ...)) { + // x86_32: call void (i32, ...) + f(22, 44); +} + +// x86_64-LABEL: @sysv +#[unsafe(no_mangle)] +#[cfg(target_arch = "x86_64")] +fn sysv(f: extern "sysv64" fn(i32, ...)) { + // x86_64: call x86_64_sysvcc void (i32, ...) + f(22, 44); +} + +// x86_64-LABEL: @win +#[unsafe(no_mangle)] +#[cfg(target_arch = "x86_64")] +fn win(f: extern "win64" fn(i32, ...)) { + // x86_64: call win64cc void (i32, ...) + f(22, 44); +} + +// CHECK-LABEL: @efiapi +#[unsafe(no_mangle)] +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "x86", + target_arch = "x86_64" +))] +fn efiapi(f: extern "efiapi" fn(i32, ...)) { + // x86_32: call void (i32, ...) + // x86_32_win: call void (i32, ...) + // x86_64: call win64cc void (i32, ...) + // aarch64: call void (i32, ...) + // arm32: call arm_aapcscc void (i32, ...) + f(22, 44); +} + +// arm32-LABEL: @aapcs +#[unsafe(no_mangle)] +#[cfg(target_arch = "arm")] +fn aapcs(f: extern "aapcs" fn(i32, ...)) { + // arm32: call arm_aapcscc void (i32, ...) + f(22, 44); +} diff --git a/tests/codegen-llvm/const-vector.rs b/tests/codegen-llvm/const-vector.rs index a2249f4fff7..f4307492341 100644 --- a/tests/codegen-llvm/const-vector.rs +++ b/tests/codegen-llvm/const-vector.rs @@ -15,6 +15,7 @@ #![feature(arm_target_feature)] #![feature(mips_target_feature)] #![allow(non_camel_case_types)] +#![feature(riscv_target_feature)] #[path = "../auxiliary/minisimd.rs"] mod minisimd; @@ -42,6 +43,7 @@ extern "unadjusted" { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] pub fn do_call() { unsafe { // CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64> diff --git a/tests/codegen-llvm/enum/enum-transparent-extract.rs b/tests/codegen-llvm/enum/enum-transparent-extract.rs new file mode 100644 index 00000000000..c5efb8d472b --- /dev/null +++ b/tests/codegen-llvm/enum/enum-transparent-extract.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Copt-level=0 +//@ only-64bit + +#![crate_type = "lib"] + +use std::ops::ControlFlow; + +pub enum Never {} + +#[no_mangle] +pub fn make_unmake_result_never(x: i32) -> i32 { + // CHECK-LABEL: define i32 @make_unmake_result_never(i32 %x) + // CHECK: start: + // CHECK-NEXT: ret i32 %x + + let y: Result<i32, Never> = Ok(x); + let Ok(z) = y; + z +} + +#[no_mangle] +pub fn extract_control_flow_never(x: ControlFlow<&str, Never>) -> &str { + // CHECK-LABEL: define { ptr, i64 } @extract_control_flow_never(ptr align 1 %x.0, i64 %x.1) + // CHECK: start: + // CHECK-NEXT: %[[P0:.+]] = insertvalue { ptr, i64 } poison, ptr %x.0, 0 + // CHECK-NEXT: %[[P1:.+]] = insertvalue { ptr, i64 } %[[P0]], i64 %x.1, 1 + // CHECK-NEXT: ret { ptr, i64 } %[[P1]] + + let ControlFlow::Break(s) = x; + s +} diff --git a/tests/codegen-llvm/intrinsics/transmute-simd.rs b/tests/codegen-llvm/intrinsics/transmute-simd.rs new file mode 100644 index 00000000000..e34b27e1333 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/transmute-simd.rs @@ -0,0 +1,176 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ only-64bit (so I don't need to worry about usize) +//@ revisions: aarch64 x86_64 +//@ [aarch64] only-aarch64 +//@ [aarch64] compile-flags: -C target-feature=+neon +//@ [x86_64] only-x86_64 +//@ [x86_64] compile-flags: -C target-feature=+sse2 + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(portable_simd)] + +use std::intrinsics::transmute; +use std::simd::{Simd, f32x4, f64x2, i32x4, i64x2}; +type PtrX2 = Simd<*const (), 2>; + +// These tests use the "C" ABI so that the vectors in question aren't passed and +// returned though memory (as they are in the "Rust" ABI), which greatly +// simplifies seeing the difference between the in-operand cases vs the ones +// that fallback to just using the `LocalKind::Memory` path. + +// CHECK-LABEL: <2 x i64> @mixed_int(<4 x i32> %v) +#[no_mangle] +pub extern "C" fn mixed_int(v: i32x4) -> i64x2 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <4 x i32> %v to <2 x i64> + // CHECK: ret <2 x i64> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x double> @mixed_float(<4 x float> %v) +#[no_mangle] +pub extern "C" fn mixed_float(v: f32x4) -> f64x2 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <4 x float> %v to <2 x double> + // CHECK: ret <2 x double> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <4 x i32> @float_int_same_lanes(<4 x float> %v) +#[no_mangle] +pub extern "C" fn float_int_same_lanes(v: f32x4) -> i32x4 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <4 x float> %v to <4 x i32> + // CHECK: ret <4 x i32> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x double> @int_float_same_lanes(<2 x i64> %v) +#[no_mangle] +pub extern "C" fn int_float_same_lanes(v: i64x2) -> f64x2 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <2 x i64> %v to <2 x double> + // CHECK: ret <2 x double> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x i64> @float_int_widen(<4 x float> %v) +#[no_mangle] +pub extern "C" fn float_int_widen(v: f32x4) -> i64x2 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <4 x float> %v to <2 x i64> + // CHECK: ret <2 x i64> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x double> @int_float_widen(<4 x i32> %v) +#[no_mangle] +pub extern "C" fn int_float_widen(v: i32x4) -> f64x2 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <4 x i32> %v to <2 x double> + // CHECK: ret <2 x double> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <4 x i32> @float_int_narrow(<2 x double> %v) +#[no_mangle] +pub extern "C" fn float_int_narrow(v: f64x2) -> i32x4 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <2 x double> %v to <4 x i32> + // CHECK: ret <4 x i32> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <4 x float> @int_float_narrow(<2 x i64> %v) +#[no_mangle] +pub extern "C" fn int_float_narrow(v: i64x2) -> f32x4 { + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = bitcast <2 x i64> %v to <4 x float> + // CHECK: ret <4 x float> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x ptr> @float_ptr_same_lanes(<2 x double> %v) +#[no_mangle] +pub extern "C" fn float_ptr_same_lanes(v: f64x2) -> PtrX2 { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca [16 x i8] + // CHECK-NOT: alloca + // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]]) + // CHECK: store <2 x double> %v, ptr %[[TEMP]] + // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]] + // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]]) + // CHECK: ret <2 x ptr> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x double> @ptr_float_same_lanes(<2 x ptr> %v) +#[no_mangle] +pub extern "C" fn ptr_float_same_lanes(v: PtrX2) -> f64x2 { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca [16 x i8] + // CHECK-NOT: alloca + // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]]) + // CHECK: store <2 x ptr> %v, ptr %[[TEMP]] + // CHECK: %[[RET:.+]] = load <2 x double>, ptr %[[TEMP]] + // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]]) + // CHECK: ret <2 x double> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x ptr> @int_ptr_same_lanes(<2 x i64> %v) +#[no_mangle] +pub extern "C" fn int_ptr_same_lanes(v: i64x2) -> PtrX2 { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca [16 x i8] + // CHECK-NOT: alloca + // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]]) + // CHECK: store <2 x i64> %v, ptr %[[TEMP]] + // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]] + // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]]) + // CHECK: ret <2 x ptr> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x i64> @ptr_int_same_lanes(<2 x ptr> %v) +#[no_mangle] +pub extern "C" fn ptr_int_same_lanes(v: PtrX2) -> i64x2 { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca [16 x i8] + // CHECK-NOT: alloca + // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]]) + // CHECK: store <2 x ptr> %v, ptr %[[TEMP]] + // CHECK: %[[RET:.+]] = load <2 x i64>, ptr %[[TEMP]] + // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]]) + // CHECK: ret <2 x i64> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x ptr> @float_ptr_widen(<4 x float> %v) +#[no_mangle] +pub extern "C" fn float_ptr_widen(v: f32x4) -> PtrX2 { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca [16 x i8] + // CHECK-NOT: alloca + // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]]) + // CHECK: store <4 x float> %v, ptr %[[TEMP]] + // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]] + // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]]) + // CHECK: ret <2 x ptr> %[[RET]] + unsafe { transmute(v) } +} + +// CHECK-LABEL: <2 x ptr> @int_ptr_widen(<4 x i32> %v) +#[no_mangle] +pub extern "C" fn int_ptr_widen(v: i32x4) -> PtrX2 { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca [16 x i8] + // CHECK-NOT: alloca + // CHECK: call void @llvm.lifetime.start.p0(i64 16, ptr %[[TEMP]]) + // CHECK: store <4 x i32> %v, ptr %[[TEMP]] + // CHECK: %[[RET:.+]] = load <2 x ptr>, ptr %[[TEMP]] + // CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr %[[TEMP]]) + // CHECK: ret <2 x ptr> %[[RET]] + unsafe { transmute(v) } +} diff --git a/tests/codegen-llvm/intrinsics/transmute.rs b/tests/codegen-llvm/intrinsics/transmute.rs index c9a1cd58af3..91cff38773d 100644 --- a/tests/codegen-llvm/intrinsics/transmute.rs +++ b/tests/codegen-llvm/intrinsics/transmute.rs @@ -191,22 +191,28 @@ pub unsafe fn check_byte_from_bool(x: bool) -> u8 { // CHECK-LABEL: @check_to_pair( #[no_mangle] pub unsafe fn check_to_pair(x: u64) -> Option<i32> { - // CHECK: %_0 = alloca [8 x i8], align 4 - // CHECK: store i64 %x, ptr %_0, align 4 + // CHECK: %[[TEMP:.+]] = alloca [8 x i8], align 8 + // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr %[[TEMP]]) + // CHECK: store i64 %x, ptr %[[TEMP]], align 8 + // CHECK: %[[PAIR0:.+]] = load i32, ptr %[[TEMP]], align 8 + // CHECK: %[[PAIR1P:.+]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 4 + // CHECK: %[[PAIR1:.+]] = load i32, ptr %[[PAIR1P]], align 4 + // CHECK: call void @llvm.lifetime.end.p0(i64 8, ptr %[[TEMP]]) + // CHECK: insertvalue {{.+}}, i32 %[[PAIR0]], 0 + // CHECK: insertvalue {{.+}}, i32 %[[PAIR1]], 1 transmute(x) } // CHECK-LABEL: @check_from_pair( #[no_mangle] pub unsafe fn check_from_pair(x: Option<i32>) -> u64 { - // The two arguments are of types that are only 4-aligned, but they're - // immediates so we can write using the destination alloca's alignment. - const { assert!(std::mem::align_of::<Option<i32>>() == 4) }; - - // CHECK: %_0 = alloca [8 x i8], align 8 - // CHECK: store i32 %x.0, ptr %_0, align 8 - // CHECK: store i32 %x.1, ptr %0, align 4 - // CHECK: %[[R:.+]] = load i64, ptr %_0, align 8 + // CHECK: %[[TEMP:.+]] = alloca [8 x i8], align 8 + // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr %[[TEMP]]) + // CHECK: store i32 %x.0, ptr %[[TEMP]], align 8 + // CHECK: %[[PAIR1P:.+]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 4 + // CHECK: store i32 %x.1, ptr %[[PAIR1P]], align 4 + // CHECK: %[[R:.+]] = load i64, ptr %[[TEMP]], align 8 + // CHECK: call void @llvm.lifetime.end.p0(i64 8, ptr %[[TEMP]]) // CHECK: ret i64 %[[R]] transmute(x) } diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs index 07b8ae6e9d7..796b69b722b 100644 --- a/tests/codegen-llvm/wasm_exceptions.rs +++ b/tests/codegen-llvm/wasm_exceptions.rs @@ -2,7 +2,7 @@ //@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh #![crate_type = "lib"] -#![feature(core_intrinsics)] +#![feature(core_intrinsics, wasm_exception_handling_intrinsics)] extern "C-unwind" { fn may_panic(); @@ -57,3 +57,17 @@ pub fn test_rtry() { // CHECK: {{.*}} = catchpad within {{.*}} [ptr null] // CHECK: catchret } + +// Make sure the intrinsic is not inferred as nounwind. This is a regression test for #132416. +// CHECK-LABEL: @test_intrinsic() {{.*}} @__gxx_wasm_personality_v0 +#[no_mangle] +pub fn test_intrinsic() { + let _log_on_drop = LogOnDrop; + unsafe { + core::arch::wasm32::throw::<0>(core::ptr::null_mut()); + } + + // CHECK-NOT: call + // CHECK: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null) + // CHECK: %cleanuppad = cleanuppad within none [] +} diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map index 53128dd7a48..9f8dc8d6cbb 100644 --- a/tests/coverage/async_closure.cov-map +++ b/tests/coverage/async_closure.cov-map @@ -37,29 +37,32 @@ Number of file 0 mappings: 8 Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 - file 0 => $DIR/async_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36) Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 - file 0 => $DIR/async_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36) Highest counter ID seen: c0 Function name: async_closure::main::{closure#0}::{closure#0}::<i16> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 - file 0 => $DIR/async_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36) Highest counter ID seen: c0 diff --git a/tests/crashes/121176.rs b/tests/crashes/121176.rs deleted file mode 100644 index 4d82e51de8f..00000000000 --- a/tests/crashes/121176.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #121176 -//@ needs-rustc-debug-assertions -use std::fmt::Debug; - -static STATIC_1: dyn Debug + Sync = *(); - -fn main() { - println!("{:?}", &STATIC_1); -} diff --git a/tests/crashes/129109.rs b/tests/crashes/129109.rs deleted file mode 100644 index 0db53b98a71..00000000000 --- a/tests/crashes/129109.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: rust-lang/rust#129109 -//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir - -extern "C" { - pub static mut symbol: [i8]; -} - -fn main() { - println!("C", unsafe { &symbol }); -} diff --git a/tests/crashes/130970.rs b/tests/crashes/130970.rs deleted file mode 100644 index 698c2b478e1..00000000000 --- a/tests/crashes/130970.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #130970 -//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir - -fn main() { - extern "C" { - static symbol: [usize]; - } - println!("{}", symbol[0]); -} diff --git a/tests/crashes/131347.rs b/tests/crashes/131347.rs deleted file mode 100644 index 08f7d068e25..00000000000 --- a/tests/crashes/131347.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #131347 -//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir - -struct S; -static STUFF: [i8] = [0; S::N]; - -fn main() { - assert_eq!(STUFF, [0; 63]); -} diff --git a/tests/debuginfo/basic-types-globals-metadata.rs b/tests/debuginfo/basic-types-globals-metadata.rs index 53fc550a2dc..aec8ff183ad 100644 --- a/tests/debuginfo/basic-types-globals-metadata.rs +++ b/tests/debuginfo/basic-types-globals-metadata.rs @@ -59,7 +59,12 @@ static mut F64: f64 = 3.5; fn main() { _zzz(); // #break - let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F16, F32, F64) }; + let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) }; + // FIXME: Including f16 and f32 in the same tuple emits `__gnu_h2f_ieee`, which + // does not exist on some targets like PowerPC. + // See https://github.com/llvm/llvm-project/issues/97981 and + // https://github.com/rust-lang/compiler-builtins/issues/655 + let b = unsafe { F16 }; } fn _zzz() {()} diff --git a/tests/debuginfo/basic-types-globals.rs b/tests/debuginfo/basic-types-globals.rs index 41b69939650..15a0deb64c1 100644 --- a/tests/debuginfo/basic-types-globals.rs +++ b/tests/debuginfo/basic-types-globals.rs @@ -63,7 +63,12 @@ static mut F64: f64 = 3.5; fn main() { _zzz(); // #break - let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F16, F32, F64) }; + let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) }; + // FIXME: Including f16 and f32 in the same tuple emits `__gnu_h2f_ieee`, which + // does not exist on some targets like PowerPC. + // See https://github.com/llvm/llvm-project/issues/97981 and + // https://github.com/rust-lang/compiler-builtins/issues/655 + let b = unsafe { F16 }; } fn _zzz() {()} diff --git a/tests/debuginfo/by-value-non-immediate-argument.rs b/tests/debuginfo/by-value-non-immediate-argument.rs index 5233b95f1f4..deacea5f6cc 100644 --- a/tests/debuginfo/by-value-non-immediate-argument.rs +++ b/tests/debuginfo/by-value-non-immediate-argument.rs @@ -3,6 +3,7 @@ //@ compile-flags:-g //@ ignore-windows-gnu: #128973 //@ ignore-aarch64-unknown-linux-gnu (gdb tries to read from 0x0; FIXME: #128973) +//@ ignore-powerpc64: #128973 on both -gnu and -musl // === GDB TESTS =================================================================================== diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index fa88211383a..d465b8bded2 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -40,7 +40,7 @@ + coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:18 (#0); + coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:23: 19:30 (#0); + coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:31: 19:32 (#0); -+ coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:1: 21:2 (#0); ++ coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:2: 21:2 (#0); + bb0: { + Coverage::VirtualCounter(bcb0); diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff index 9b6d2b22087..cf6d85abd80 100644 --- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff @@ -6,7 +6,7 @@ + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 27:17 (#0); + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:28:5: 28:9 (#0); -+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:1: 29:2 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:2: 29:2 (#0); + bb0: { + Coverage::VirtualCounter(bcb0); diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff index b2bb2375aee..980c5e202ff 100644 --- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff @@ -10,8 +10,8 @@ + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:10 (#0); + coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:15 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:16:13: 16:18 (#0); -+ coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:9: 17:10 (#0); -+ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:1: 19:2 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:10: 17:10 (#0); ++ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:2: 19:2 (#0); + bb0: { + Coverage::VirtualCounter(bcb0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff index 2eb78c08ee8..b707cd41788 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff @@ -10,8 +10,8 @@ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0); coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0); - coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0); - coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0); + coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0); coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); bb0: { diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff index 0c1bc24b6dc..239b845c231 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff @@ -10,8 +10,8 @@ + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0); + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); + coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0); -+ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0); -+ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0); ++ coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0); + coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); + bb0: { diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir index 5876c55c52b..b5c23822162 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir @@ -8,12 +8,14 @@ fn num_to_digit(_1: char) -> u32 { let _2: std::option::Option<u32>; scope 2 (inlined Option::<u32>::is_some) { let mut _3: isize; + scope 3 { + } } } - scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { + scope 4 (inlined #[track_caller] Option::<u32>::unwrap) { let mut _5: isize; let mut _6: !; - scope 4 { + scope 5 { } } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir index f1185353a43..f22b8835735 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir @@ -8,12 +8,14 @@ fn num_to_digit(_1: char) -> u32 { let _2: std::option::Option<u32>; scope 2 (inlined Option::<u32>::is_some) { let mut _3: isize; + scope 3 { + } } } - scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { + scope 4 (inlined #[track_caller] Option::<u32>::unwrap) { let mut _5: isize; let mut _6: !; - scope 4 { + scope 5 { } } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir index 5876c55c52b..b5c23822162 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir @@ -8,12 +8,14 @@ fn num_to_digit(_1: char) -> u32 { let _2: std::option::Option<u32>; scope 2 (inlined Option::<u32>::is_some) { let mut _3: isize; + scope 3 { + } } } - scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { + scope 4 (inlined #[track_caller] Option::<u32>::unwrap) { let mut _5: isize; let mut _6: !; - scope 4 { + scope 5 { } } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir index f1185353a43..f22b8835735 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir @@ -8,12 +8,14 @@ fn num_to_digit(_1: char) -> u32 { let _2: std::option::Option<u32>; scope 2 (inlined Option::<u32>::is_some) { let mut _3: isize; + scope 3 { + } } } - scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { + scope 4 (inlined #[track_caller] Option::<u32>::unwrap) { let mut _5: isize; let mut _6: !; - scope 4 { + scope 5 { } } diff --git a/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff index 281f43b355d..3ce82fd0d47 100644 --- a/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff @@ -7,6 +7,8 @@ let mut _2: bool; let mut _3: isize; + let mut _4: isize; + scope 1 { + } bb0: { StorageLive(_2); diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index 1a1c8b4b942..83478e60b5d 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -25,9 +25,11 @@ fn step_forward(_1: u16, _2: usize) -> u16 { } scope 8 (inlined Option::<u16>::is_none) { scope 9 (inlined Option::<u16>::is_some) { + scope 10 { + } } } - scope 10 (inlined core::num::<impl u16>::wrapping_add) { + scope 11 (inlined core::num::<impl u16>::wrapping_add) { } } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index e7e19af048a..ac7a6e04451 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -25,9 +25,11 @@ fn step_forward(_1: u16, _2: usize) -> u16 { } scope 8 (inlined Option::<u16>::is_none) { scope 9 (inlined Option::<u16>::is_some) { + scope 10 { + } } } - scope 10 (inlined core::num::<impl u16>::wrapping_add) { + scope 11 (inlined core::num::<impl u16>::wrapping_add) { } } diff --git a/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir index d41135c6a4f..2d6f82f6137 100644 --- a/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir @@ -4,6 +4,8 @@ fn issue_77355_opt(_1: Foo) -> u64 { debug num => _1; let mut _0: u64; let mut _2: isize; + scope 1 { + } bb0: { _2 = discriminant(_1); diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 57b68c65930..9ea706af503 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -64,7 +64,9 @@ fn main() { .normalize(r#"/rustc[^/_-]*/"#, "/rustc/") .normalize("libpanic_abort", "libpanic_unwind") .normalize( - regex::escape(run_make_support::build_root().to_str().unwrap()), + regex::escape( + run_make_support::build_root().canonicalize().unwrap().to_str().unwrap(), + ), "/build-root", ) .normalize(r#""[^"]*\/symbols.o""#, "\"/symbols.o\"") diff --git a/tests/run-make/rustdoc-target-modifiers/c.rs b/tests/run-make/rustdoc-target-modifiers/c.rs new file mode 100644 index 00000000000..287d0bbd725 --- /dev/null +++ b/tests/run-make/rustdoc-target-modifiers/c.rs @@ -0,0 +1,7 @@ +#![allow(internal_features)] +#![feature(lang_items, no_core)] +#![no_core] + +fn f() { + d::f(); +} diff --git a/tests/run-make/rustdoc-target-modifiers/d.rs b/tests/run-make/rustdoc-target-modifiers/d.rs new file mode 100644 index 00000000000..6cbff06079e --- /dev/null +++ b/tests/run-make/rustdoc-target-modifiers/d.rs @@ -0,0 +1,12 @@ +#![allow(internal_features)] +#![feature(lang_items, no_core)] +#![no_core] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} +#[lang = "sized"] +pub trait Sized: MetaSized {} + +pub fn f() {} diff --git a/tests/run-make/rustdoc-target-modifiers/rmake.rs b/tests/run-make/rustdoc-target-modifiers/rmake.rs new file mode 100644 index 00000000000..ee522501fd2 --- /dev/null +++ b/tests/run-make/rustdoc-target-modifiers/rmake.rs @@ -0,0 +1,28 @@ +//! Test that target modifiers are taken into account by `rustdoc`. +//! +//! Otherwise, `rustdoc` errors when trying to generate documentation +//! using dependencies (e.g. `core`) that set a target modifier. +//! +//! Please see https://github.com/rust-lang/rust/issues/144521. + +use run_make_support::{rustc, rustdoc}; + +fn main() { + rustc() + .input("d.rs") + .edition("2024") + .crate_type("rlib") + .emit("metadata") + .sysroot("/dev/null") + .target("aarch64-unknown-none-softfloat") + .arg("-Zfixed-x18") + .run(); + + rustdoc() + .input("c.rs") + .crate_type("rlib") + .extern_("d", "libd.rmeta") + .target("aarch64-unknown-none-softfloat") + .arg("-Zfixed-x18") + .run(); +} diff --git a/tests/run-make/uefi-qemu/rmake.rs b/tests/run-make/uefi-qemu/rmake.rs new file mode 100644 index 00000000000..55d42fba5e7 --- /dev/null +++ b/tests/run-make/uefi-qemu/rmake.rs @@ -0,0 +1,84 @@ +//! This test builds and runs a basic UEFI application on QEMU for various targets. +//! +//! You must have the relevant OVMF or AAVMF firmware installed for this to work. +//! +//! Requires: qemu-system-x86_64, qemu-system-aarch64 +//! OVMF/AAVMF firmware +//! +//! Note: test assumes `/uefi_qemu_test` exists and is a self-contained crate. + +//@ only-uefi + +use std::path::Path; + +use run_make_support::{cargo, cmd, path, rfs}; + +fn main() { + let target = run_make_support::target(); + + let (boot_filename, ovmf_dir, ovmf_code_name, ovmf_vars_name, qemu, machine, cpu) = + match target.as_str() { + "aarch64-unknown-uefi" => ( + "bootaa64.efi", + Path::new("/usr/share/AAVMF"), + "AAVMF_CODE.fd", + "AAVMF_VARS.fd", + "qemu-system-aarch64", + "virt", + "cortex-a72", + ), + "i686-unknown-uefi" => ( + "bootia32.efi", + Path::new("/usr/share/OVMF"), + "OVMF32_CODE_4M.secboot.fd", + "OVMF32_VARS_4M.fd", + "qemu-system-x86_64", + "q35", + "qemu64", + ), + "x86_64-unknown-uefi" => ( + "bootx64.efi", + Path::new("/usr/share/OVMF"), + "OVMF_CODE_4M.fd", + "OVMF_VARS_4M.fd", + "qemu-system-x86_64", + "q35", + "qemu64", + ), + _ => panic!("unsupported target {target}"), + }; + + let tmp = std::env::temp_dir(); + let test_crate = tmp.join("uefi_qemu_test"); + rfs::copy_dir_all(path("uefi_qemu_test"), &test_crate); + + cargo().args(&["build", "--target", &target]).current_dir(&test_crate).run(); + + // Prepare ESP + let esp = test_crate.join("esp"); + let boot = esp.join("efi/boot"); + rfs::create_dir_all(&boot); + + let src_efi = test_crate.join("target").join(&target).join("debug/uefi_qemu_test.efi"); + let dst_efi = boot.join(boot_filename); + rfs::copy(&src_efi, &dst_efi); + + // Copy OVMF files + let code = ovmf_dir.join(ovmf_code_name); + let vars_src = ovmf_dir.join(ovmf_vars_name); + let vars_dst = tmp.join("vars.fd"); + rfs::copy(&vars_src, &vars_dst); + + let output = cmd(qemu) + .args(["-machine", machine]) + .args(["-cpu", cpu]) + .args(["-display", "none"]) + .args(["-serial", "stdio"]) + .args(["-drive", &format!("if=pflash,format=raw,readonly=on,file={}", code.display())]) + .args(["-drive", &format!("if=pflash,format=raw,readonly=off,file={}", vars_dst.display())]) + .args(["-drive", &format!("format=raw,file=fat:rw:{}", esp.display())]) + .run() + .stdout_utf8(); + + assert!(output.contains("Hello World!"), "invalid output for {target}:\n{output}"); +} diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.lock index 8b6a664ad93..8b6a664ad93 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock +++ b/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.lock diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml b/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.toml index 1a8d0d94368..1a8d0d94368 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml +++ b/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.toml diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs b/tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs index 89e4393cb5c..f8e1212a9f6 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs +++ b/tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs @@ -15,14 +15,7 @@ fn panic_handler(_info: &panic::PanicInfo) -> ! { #[export_name = "efi_main"] pub extern "C" fn main(_h: Handle, st: *mut SystemTable) -> Status { - let s = [ - 0x0048u16, 0x0065u16, 0x006cu16, 0x006cu16, 0x006fu16, // "Hello" - 0x0020u16, // " " - 0x0057u16, 0x006fu16, 0x0072u16, 0x006cu16, 0x0064u16, // "World" - 0x0021u16, // "!" - 0x000au16, // "\n" - 0x0000u16, // NUL - ]; + let s = b"Hello World!\n\0".map(|c| u16::from(c)); // Print "Hello World!". let r = unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut Char16) }; diff --git a/tests/ui/README.md b/tests/ui/README.md index b635b6326fc..86c9ad9c1ce 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -412,6 +412,10 @@ These tests revolve around command-line flags which change the way error/warning Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md). +## `tests/ui/diagnostics-infra` + +This directory contains tests and infrastructure related to the diagnostics system, including support for translatable diagnostics + ## `tests/ui/diagnostic-width/`: `--diagnostic-width` Everything to do with `--diagnostic-width`. @@ -1233,6 +1237,10 @@ Exercises sanitizer support. See [Sanitizer | The rustc book](https://doc.rust-l Tests with erroneous ways of using `self`, such as using `this.x` syntax as seen in other languages, having it not be the first argument, or using it in a non-associated function (no `impl` or `trait`). It also contains correct uses of `self` which have previously been observed to cause ICEs. +## `tests/ui/self-profile/`: self-profiling + +Tests related to the self-profiler (`-Zself-profile`) functionality of rustc. + ## `tests/ui/sepcomp/`: Separate Compilation In this directory, multiple crates are compiled, but some of them have `inline` functions, meaning they must be inlined into a different crate despite having been compiled separately. diff --git a/tests/ui/allocator/no_std-alloc-error-handler-custom.rs b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs index 1b0f0608fc6..7b7ca2f6cc6 100644 --- a/tests/ui/allocator/no_std-alloc-error-handler-custom.rs +++ b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs @@ -2,6 +2,7 @@ //@ ignore-android no libc //@ ignore-emscripten no libc //@ ignore-sgx no libc +//@ ignore-backends: gcc //@ only-linux //@ compile-flags:-C panic=abort //@ aux-build:helper.rs diff --git a/tests/ui/allocator/no_std-alloc-error-handler-default.rs b/tests/ui/allocator/no_std-alloc-error-handler-default.rs index 51ecf1a6731..5a6c0b33d51 100644 --- a/tests/ui/allocator/no_std-alloc-error-handler-default.rs +++ b/tests/ui/allocator/no_std-alloc-error-handler-default.rs @@ -2,6 +2,7 @@ //@ ignore-android no libc //@ ignore-emscripten no libc //@ ignore-sgx no libc +//@ ignore-backends: gcc //@ only-linux //@ compile-flags:-C panic=abort //@ aux-build:helper.rs diff --git a/tests/ui/asm/may_unwind.rs b/tests/ui/asm/may_unwind.rs index 1d4f50d5fe8..0fef317a2cf 100644 --- a/tests/ui/asm/may_unwind.rs +++ b/tests/ui/asm/may_unwind.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-asm-support //@ needs-unwind +//@ ignore-backends: gcc #![feature(asm_unwind)] diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs index 996fb82a944..e78553fd775 100644 --- a/tests/ui/asm/named-asm-labels.rs +++ b/tests/ui/asm/named-asm-labels.rs @@ -171,12 +171,10 @@ fn main() { } } -// Trigger on naked fns too, even though they can't be inlined, reusing a -// label or LTO can cause labels to break +// Don't trigger on naked functions. #[unsafe(naked)] pub extern "C" fn foo() -> i32 { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) - //~^ ERROR avoid using named labels } // Make sure that non-naked attributes *do* still let the lint happen @@ -190,7 +188,18 @@ pub extern "C" fn bar() { pub extern "C" fn aaa() { fn _local() {} - naked_asm!(".Laaa: nop; ret;") //~ ERROR avoid using named labels + naked_asm!(".Laaa: nop; ret;") +} + +#[unsafe(naked)] +pub extern "C" fn bbb<'a>(a: &'a u32) { + naked_asm!(".Lbbb: nop; ret;") +} + +#[unsafe(naked)] +pub extern "C" fn ccc<T>(a: &T) { + naked_asm!(".Lccc: nop; ret;") + //~^ ERROR avoid using named labels } pub fn normal() { @@ -200,7 +209,7 @@ pub fn normal() { pub extern "C" fn bbb() { fn _very_local() {} - naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels + naked_asm!(".Lbbb: nop; ret;") } fn _local2() {} @@ -230,3 +239,10 @@ fn closures() { // Don't trigger on global asm global_asm!("aaaaaaaa: nop"); + +trait Foo { + #[unsafe(naked)] + extern "C" fn bbb<'a>(a: &'a u32) { + naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels + } +} diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr index cd7e7a08c1d..9ba9e14de3a 100644 --- a/tests/ui/asm/named-asm-labels.stderr +++ b/tests/ui/asm/named-asm-labels.stderr @@ -475,16 +475,7 @@ LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:178:17 - | -LL | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) - | ^^^^^ - | - = help: only local labels of the form `<number>:` should be used in inline asm - = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information - -error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:185:20 + --> $DIR/named-asm-labels.rs:183:20 | LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } | ^^^^^ @@ -493,49 +484,49 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:193:17 + --> $DIR/named-asm-labels.rs:201:17 | -LL | naked_asm!(".Laaa: nop; ret;") +LL | naked_asm!(".Lccc: nop; ret;") | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:203:21 + --> $DIR/named-asm-labels.rs:221:15 | -LL | naked_asm!(".Lbbb: nop; ret;") - | ^^^^^ +LL | asm!("closure1: nop"); + | ^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:212:15 + --> $DIR/named-asm-labels.rs:225:15 | -LL | asm!("closure1: nop"); +LL | asm!("closure2: nop"); | ^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:216:15 + --> $DIR/named-asm-labels.rs:235:19 | -LL | asm!("closure2: nop"); - | ^^^^^^^^ +LL | asm!("closure3: nop"); + | ^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:226:19 + --> $DIR/named-asm-labels.rs:246:21 | -LL | asm!("closure3: nop"); - | ^^^^^^^^ +LL | naked_asm!(".Lbbb: nop; ret;") + | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information -error: aborting due to 56 previous errors; 1 warning emitted +error: aborting due to 55 previous errors; 1 warning emitted diff --git a/tests/ui/asm/x86_64/may_unwind.rs b/tests/ui/asm/x86_64/may_unwind.rs index d3a2916df9d..9657f49ab30 100644 --- a/tests/ui/asm/x86_64/may_unwind.rs +++ b/tests/ui/asm/x86_64/may_unwind.rs @@ -2,6 +2,7 @@ //@ run-pass //@ needs-asm-support //@ needs-unwind +//@ ignore-backends: gcc #![feature(asm_unwind)] diff --git a/tests/ui/async-await/deep-futures-are-freeze.rs b/tests/ui/async-await/deep-futures-are-freeze.rs index c4300163db1..79dbc033bf7 100644 --- a/tests/ui/async-await/deep-futures-are-freeze.rs +++ b/tests/ui/async-await/deep-futures-are-freeze.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ build-pass //@ compile-flags: -Copt-level=s -Clto=fat //@ no-prefer-dynamic diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs index 4bafb39f600..d6180bb2f45 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ edition: 2021 //@ known-bug: #108309 diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 62cca41f6cf..3d82f572a1a 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -1,11 +1,11 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/dont-project-to-specializable-projection.rs:13:5 + --> $DIR/dont-project-to-specializable-projection.rs:14:5 | LL | default async fn foo(_: T) -> &'static str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found future | note: type in trait - --> $DIR/dont-project-to-specializable-projection.rs:9:5 + --> $DIR/dont-project-to-specializable-projection.rs:10:5 | LL | async fn foo(_: T) -> &'static str; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | async fn foo(_: T) -> &'static str; found signature `fn(_) -> impl Future<Output = &'static str>` error: async associated function in trait cannot be specialized - --> $DIR/dont-project-to-specializable-projection.rs:13:5 + --> $DIR/dont-project-to-specializable-projection.rs:14:5 | LL | default async fn foo(_: T) -> &'static str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | default async fn foo(_: T) -> &'static str { = note: specialization behaves in inconsistent and surprising ways with async functions in traits, and for now is disallowed error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future<Output = ()>>` in the current scope - --> $DIR/dont-project-to-specializable-projection.rs:48:28 + --> $DIR/dont-project-to-specializable-projection.rs:49:28 | LL | match fut.as_mut().poll(ctx) { | ^^^^ method not found in `Pin<&mut impl Future<Output = ()>>` diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 7ae24db8b5f..814a1e5f691 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -43,12 +43,6 @@ error: malformed `no_sanitize` attribute input LL | #[no_sanitize] | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]` -error: malformed `proc_macro` attribute input - --> $DIR/malformed-attrs.rs:100:1 - | -LL | #[proc_macro = 18] - | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` - error: malformed `instruction_set` attribute input --> $DIR/malformed-attrs.rs:107:1 | @@ -67,18 +61,6 @@ error: malformed `coroutine` attribute input LL | #[coroutine = 63] || {} | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]` -error: malformed `proc_macro_attribute` attribute input - --> $DIR/malformed-attrs.rs:117:1 - | -LL | #[proc_macro_attribute = 19] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` - -error: malformed `proc_macro_derive` attribute input - --> $DIR/malformed-attrs.rs:124:1 - | -LL | #[proc_macro_derive] - | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` - error: malformed `must_not_suspend` attribute input --> $DIR/malformed-attrs.rs:133:1 | @@ -454,6 +436,24 @@ LL | #[no_implicit_prelude = 23] | | didn't expect any arguments here | help: must be of the form: `#[no_implicit_prelude]` +error[E0565]: malformed `proc_macro` attribute input + --> $DIR/malformed-attrs.rs:100:1 + | +LL | #[proc_macro = 18] + | ^^^^^^^^^^^^^----^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro]` + +error[E0565]: malformed `proc_macro_attribute` attribute input + --> $DIR/malformed-attrs.rs:117:1 + | +LL | #[proc_macro_attribute = 19] + | ^^^^^^^^^^^^^^^^^^^^^^^----^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_attribute]` + error[E0539]: malformed `must_use` attribute input --> $DIR/malformed-attrs.rs:120:1 | @@ -471,6 +471,15 @@ LL - #[must_use = 1] LL + #[must_use] | +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/malformed-attrs.rs:124:1 + | +LL | #[proc_macro_derive] + | ^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` + error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input --> $DIR/malformed-attrs.rs:129:1 | diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs index 2f17d9620b4..bd136e64d3f 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -12,6 +12,7 @@ pub fn b() {} #[proc_macro_derive(unsafe(Foo))] //~^ ERROR attribute is only usable with crates of the `proc-macro` crate type //~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR malformed `proc_macro_derive` attribute input pub fn c() {} #[unsafe(proc_macro_attribute)] diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 25b83a26e17..884e7663c85 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -1,11 +1,11 @@ error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:26:16 + --> $DIR/proc-unsafe-attributes.rs:27:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:26:16 + --> $DIR/proc-unsafe-attributes.rs:27:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument @@ -40,7 +40,7 @@ LL | #[proc_macro_derive(r#unsafe(Foo))] | ++ error: `proc_macro_attribute` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:17:3 + --> $DIR/proc-unsafe-attributes.rs:18:3 | LL | #[unsafe(proc_macro_attribute)] | ^^^^^^ this is not an unsafe attribute @@ -48,7 +48,7 @@ LL | #[unsafe(proc_macro_attribute)] = note: extraneous unsafe is not allowed in attributes error: `allow` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:22:3 + --> $DIR/proc-unsafe-attributes.rs:23:3 | LL | #[unsafe(allow(dead_code))] | ^^^^^^ this is not an unsafe attribute @@ -56,7 +56,7 @@ LL | #[unsafe(allow(dead_code))] = note: extraneous unsafe is not allowed in attributes error: `allow` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:26:3 + --> $DIR/proc-unsafe-attributes.rs:27:3 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^ this is not an unsafe attribute @@ -64,7 +64,7 @@ LL | #[unsafe(allow(unsafe(dead_code)))] = note: extraneous unsafe is not allowed in attributes error: expected identifier, found keyword `unsafe` - --> $DIR/proc-unsafe-attributes.rs:26:16 + --> $DIR/proc-unsafe-attributes.rs:27:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^ expected identifier, found keyword @@ -93,13 +93,13 @@ LL | #[proc_macro_derive(unsafe(Foo))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/proc-unsafe-attributes.rs:17:1 + --> $DIR/proc-unsafe-attributes.rs:18:1 | LL | #[unsafe(proc_macro_attribute)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:26:16 + --> $DIR/proc-unsafe-attributes.rs:27:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument @@ -107,15 +107,24 @@ LL | #[unsafe(allow(unsafe(dead_code)))] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:26:16 + --> $DIR/proc-unsafe-attributes.rs:27:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0565]: malformed `proc_macro_derive` attribute input + --> $DIR/proc-unsafe-attributes.rs:12:1 + | +LL | #[proc_macro_derive(unsafe(Foo))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` + error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:26:16 + --> $DIR/proc-unsafe-attributes.rs:27:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument @@ -123,13 +132,14 @@ LL | #[unsafe(allow(unsafe(dead_code)))] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:26:16 + --> $DIR/proc-unsafe-attributes.rs:27:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 17 previous errors +error: aborting due to 18 previous errors -For more information about this error, try `rustc --explain E0452`. +Some errors have detailed explanations: E0452, E0565. +For more information about an error, try `rustc --explain E0452`. diff --git a/tests/ui/backtrace/dylib-dep.rs b/tests/ui/backtrace/dylib-dep.rs index a41931ad548..05fdb9afef8 100644 --- a/tests/ui/backtrace/dylib-dep.rs +++ b/tests/ui/backtrace/dylib-dep.rs @@ -8,6 +8,7 @@ //@ ignore-fuchsia Backtraces not symbolized //@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written). //@ needs-unwind +//@ ignore-backends: gcc //@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes //@ ignore-emscripten Requires custom symbolization code //@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs diff --git a/tests/ui/borrowck/borrowck-partial-reinit-1.stderr b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr index 65f2bd6cfbd..d261f3ac572 100644 --- a/tests/ui/borrowck/borrowck-partial-reinit-1.stderr +++ b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr @@ -8,6 +8,15 @@ LL | drop(t); | - value moved here LL | t.b = Some(u); | ^^^ value assigned here after move + | +note: if `Test2` implemented `Clone`, you could clone the value + --> $DIR/borrowck-partial-reinit-1.rs:3:1 + | +LL | struct Test2 { + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(t); + | - you could clone this value error[E0382]: assign of moved value: `t` --> $DIR/borrowck-partial-reinit-1.rs:33:5 @@ -19,6 +28,15 @@ LL | drop(t); | - value moved here LL | t.0 = Some(u); | ^^^ value assigned here after move + | +note: if `Test3` implemented `Clone`, you could clone the value + --> $DIR/borrowck-partial-reinit-1.rs:7:1 + | +LL | struct Test3(Option<Test>); + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(t); + | - you could clone this value error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-partial-reinit-2.stderr b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr index e25ca082b7b..dde70eb444e 100644 --- a/tests/ui/borrowck/borrowck-partial-reinit-2.stderr +++ b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr @@ -7,6 +7,15 @@ LL | let mut u = Test { a: 2, b: Some(Box::new(t))}; | - value moved here LL | t.b = Some(Box::new(u)); | ^^^ value assigned here after move + | +note: if `Test` implemented `Clone`, you could clone the value + --> $DIR/borrowck-partial-reinit-2.rs:1:1 + | +LL | struct Test { + | ^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let mut u = Test { a: 2, b: Some(Box::new(t))}; + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-union-move-assign.stderr b/tests/ui/borrowck/borrowck-union-move-assign.stderr index 8c0239a3ae9..8721481dc1d 100644 --- a/tests/ui/borrowck/borrowck-union-move-assign.stderr +++ b/tests/ui/borrowck/borrowck-union-move-assign.stderr @@ -7,6 +7,15 @@ LL | let a = u.a; | --- value moved here LL | let a = u.a; | ^^^ value used here after move + | +note: if `U` implemented `Clone`, you could clone the value + --> $DIR/borrowck-union-move-assign.rs:7:1 + | +LL | union U { + | ^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.a; + | --- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-union-move.stderr b/tests/ui/borrowck/borrowck-union-move.stderr index 731607fbdd1..0bae7ac5227 100644 --- a/tests/ui/borrowck/borrowck-union-move.stderr +++ b/tests/ui/borrowck/borrowck-union-move.stderr @@ -7,6 +7,15 @@ LL | let a = u.n1; | ---- value moved here LL | let a = u.n1; | ^^^^ value used here after move + | +note: if `Unn` implemented `Clone`, you could clone the value + --> $DIR/borrowck-union-move.rs:7:1 + | +LL | union Unn { + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.n1; + | ---- you could clone this value error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:31:21 @@ -17,6 +26,15 @@ LL | let a = u.n1; | ---- value moved here LL | let a = u; | ^ value used here after move + | +note: if `Unn` implemented `Clone`, you could clone the value + --> $DIR/borrowck-union-move.rs:7:1 + | +LL | union Unn { + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.n1; + | ---- you could clone this value error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:36:21 @@ -27,6 +45,15 @@ LL | let a = u.n1; | ---- value moved here LL | let a = u.n2; | ^^^^ value used here after move + | +note: if `Unn` implemented `Clone`, you could clone the value + --> $DIR/borrowck-union-move.rs:7:1 + | +LL | union Unn { + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.n1; + | ---- you could clone this value error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:63:21 @@ -37,6 +64,15 @@ LL | let a = u.n; | --- value moved here LL | let a = u.n; | ^^^ value used here after move + | +note: if `Ucn` implemented `Clone`, you could clone the value + --> $DIR/borrowck-union-move.rs:15:1 + | +LL | union Ucn { + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.n; + | --- you could clone this value error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:68:21 @@ -47,6 +83,15 @@ LL | let a = u.n; | --- value moved here LL | let a = u.c; | ^^^ value used here after move + | +note: if `Ucn` implemented `Clone`, you could clone the value + --> $DIR/borrowck-union-move.rs:15:1 + | +LL | union Ucn { + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.n; + | --- you could clone this value error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:83:21 @@ -57,6 +102,15 @@ LL | let a = u.n; | --- value moved here LL | let a = u; | ^ value used here after move + | +note: if `Ucn` implemented `Clone`, you could clone the value + --> $DIR/borrowck-union-move.rs:15:1 + | +LL | union Ucn { + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.n; + | --- you could clone this value error: aborting due to 6 previous errors diff --git a/tests/ui/issues/issue-11192.rs b/tests/ui/borrowck/closure-borrow-conflict-11192.rs index 1a3d8c9fe58..dff70d62d6f 100644 --- a/tests/ui/issues/issue-11192.rs +++ b/tests/ui/borrowck/closure-borrow-conflict-11192.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11192 + struct Foo { x: isize } diff --git a/tests/ui/issues/issue-11192.stderr b/tests/ui/borrowck/closure-borrow-conflict-11192.stderr index a8a18c49549..f1df635276b 100644 --- a/tests/ui/issues/issue-11192.stderr +++ b/tests/ui/borrowck/closure-borrow-conflict-11192.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable - --> $DIR/issue-11192.rs:20:10 + --> $DIR/closure-borrow-conflict-11192.rs:22:10 | LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr index b188766e221..167fd6b227f 100644 --- a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr @@ -17,6 +17,15 @@ LL | drop(u); | - value moved here LL | u.0 = S(1); | ^^^^^^^^^^ value partially assigned here after move + | +note: if `Tpair` implemented `Clone`, you could clone the value + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:6:1 + | +LL | struct Tpair(S, i32); + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(u); + | - you could clone this value error[E0382]: assign to part of moved value: `v` --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:31:9 @@ -27,6 +36,15 @@ LL | drop(v); | - value moved here LL | v.x = S(1); | ^^^^^^^^^^ value partially assigned here after move + | +note: if `Spair` implemented `Clone`, you could clone the value + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:7:1 + | +LL | struct Spair { x: S, y: i32 } + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(v); + | - you could clone this value error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr index 774b6cf0ea6..78c5040e52a 100644 --- a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr @@ -50,6 +50,15 @@ LL | drop(u); | - value moved here LL | u.0 = S(1); | ^^^^^^^^^^ value partially assigned here after move + | +note: if `Tpair` implemented `Clone`, you could clone the value + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:6:1 + | +LL | struct Tpair(S, i32); + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(u); + | - you could clone this value error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9 @@ -82,6 +91,15 @@ LL | drop(v); | - value moved here LL | v.x = S(1); | ^^^^^^^^^^ value partially assigned here after move + | +note: if `Spair` implemented `Clone`, you could clone the value + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:7:1 + | +LL | struct Spair { x: S, y: i32 } + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(v); + | - you could clone this value error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9 diff --git a/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr index 121c2e870e7..5a0d353a481 100644 --- a/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr +++ b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr @@ -4,6 +4,14 @@ error[E0507]: cannot move out of `*array` which is behind a shared reference LL | *array | ^^^^^^ move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait | +note: if `Value` implemented `Clone`, you could clone the value + --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:4:1 + | +LL | struct Value; + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | *array + | ------ you could clone this value help: consider removing the dereference here | LL - *array diff --git a/tests/ui/c-variadic/same-program-multiple-abis.rs b/tests/ui/c-variadic/same-program-multiple-abis.rs new file mode 100644 index 00000000000..b21accb999e --- /dev/null +++ b/tests/ui/c-variadic/same-program-multiple-abis.rs @@ -0,0 +1,112 @@ +#![feature(extended_varargs_abi_support)] +//@ run-pass +//@ only-x86_64 + +// Check that multiple c-variadic calling conventions can be used in the same program. +// +// Clang and gcc reject defining functions with a non-default calling convention and a variable +// argument list, so C programs that use multiple c-variadic calling conventions are unlikely +// to come up. Here we validate that our codegen backends do in fact generate correct code. + +extern "sysv64" { + fn variadic_sysv64(_: u32, _: ...) -> u32; +} + +extern "win64" { + fn variadic_win64(_: u32, _: ...) -> u32; +} + +fn main() { + unsafe { + assert_eq!(variadic_win64(1, 2, 3), 1 + 2 + 3); + assert_eq!(variadic_sysv64(1, 2, 3), 1 + 2 + 3); + } +} + +// This assembly was generated using https://godbolt.org/z/dbTGanoh6, and corresponds to the +// following code compiled for the `x86_64-unknown-linux-gnu` and `x86_64-pc-windows-gnu` +// targets, respectively: +// +// ```rust +// #![feature(c_variadic)] +// +// #[unsafe(no_mangle)] +// unsafe extern "C" fn variadic(a: u32, mut args: ...) -> u32 { +// let b = args.arg::<u32>(); +// let c = args.arg::<u32>(); +// +// a + b + c +// } +// ``` +core::arch::global_asm!( + r#" +{variadic_sysv64}: + sub rsp, 88 + test al, al + je .LBB0_7 + movaps xmmword ptr [rsp - 48], xmm0 + movaps xmmword ptr [rsp - 32], xmm1 + movaps xmmword ptr [rsp - 16], xmm2 + movaps xmmword ptr [rsp], xmm3 + movaps xmmword ptr [rsp + 16], xmm4 + movaps xmmword ptr [rsp + 32], xmm5 + movaps xmmword ptr [rsp + 48], xmm6 + movaps xmmword ptr [rsp + 64], xmm7 +.LBB0_7: + mov qword ptr [rsp - 88], rsi + mov qword ptr [rsp - 80], rdx + mov qword ptr [rsp - 72], rcx + mov qword ptr [rsp - 64], r8 + mov qword ptr [rsp - 56], r9 + movabs rax, 206158430216 + mov qword ptr [rsp - 120], rax + lea rax, [rsp + 96] + mov qword ptr [rsp - 112], rax + lea rax, [rsp - 96] + mov qword ptr [rsp - 104], rax + mov edx, 8 + cmp rdx, 41 + jae .LBB0_1 + mov rax, qword ptr [rsp - 104] + mov ecx, 8 + add rcx, 8 + mov dword ptr [rsp - 120], ecx + mov eax, dword ptr [rax + rdx] + cmp edx, 32 + ja .LBB0_2 + add rcx, qword ptr [rsp - 104] + add edx, 16 + mov dword ptr [rsp - 120], edx + add eax, edi + add eax, dword ptr [rcx] + add rsp, 88 + ret +.LBB0_1: + mov rax, qword ptr [rsp - 112] + lea rcx, [rax + 8] + mov qword ptr [rsp - 112], rcx + mov eax, dword ptr [rax] +.LBB0_2: + mov rcx, qword ptr [rsp - 112] + lea rdx, [rcx + 8] + mov qword ptr [rsp - 112], rdx + add eax, edi + add eax, dword ptr [rcx] + add rsp, 88 + ret + +{variadic_win64}: + push rax + mov qword ptr [rsp + 40], r9 + mov qword ptr [rsp + 24], rdx + mov qword ptr [rsp + 32], r8 + lea rax, [rsp + 40] + mov qword ptr [rsp], rax + lea eax, [rdx + rcx] + add eax, r8d + pop rcx + ret + "#, + variadic_win64 = sym variadic_win64, + variadic_sysv64 = sym variadic_sysv64, +); diff --git a/tests/ui/c-variadic/variadic-ffi-1.rs b/tests/ui/c-variadic/variadic-ffi-1.rs index cd8f2a951ef..2baa00a079a 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.rs +++ b/tests/ui/c-variadic/variadic-ffi-1.rs @@ -12,6 +12,11 @@ extern "stdcall" { //~^ ERROR: C-variadic functions with the "stdcall" calling convention are not supported } +fn baz(f: extern "Rust" fn(usize, ...)) { + //~^ ERROR: C-variadic functions with the "Rust" calling convention are not supported + f(22, 44); +} + extern "C" { fn foo(f: isize, x: u8, ...); } diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr index a49fc0ce126..981b021276d 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.stderr +++ b/tests/ui/c-variadic/variadic-ffi-1.stderr @@ -4,14 +4,20 @@ error[E0045]: C-variadic functions with the "stdcall" calling convention are not LL | fn printf(_: *const u8, ...); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention +error[E0045]: C-variadic functions with the "Rust" calling convention are not supported + --> $DIR/variadic-ffi-1.rs:15:11 + | +LL | fn baz(f: extern "Rust" fn(usize, ...)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention + error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied - --> $DIR/variadic-ffi-1.rs:23:9 + --> $DIR/variadic-ffi-1.rs:28:9 | LL | foo(); | ^^^-- two arguments of type `isize` and `u8` are missing | note: function defined here - --> $DIR/variadic-ffi-1.rs:16:8 + --> $DIR/variadic-ffi-1.rs:21:8 | LL | fn foo(f: isize, x: u8, ...); | ^^^ - - @@ -21,13 +27,13 @@ LL | foo(/* isize */, /* u8 */); | +++++++++++++++++++++ error[E0060]: this function takes at least 2 arguments but 1 argument was supplied - --> $DIR/variadic-ffi-1.rs:24:9 + --> $DIR/variadic-ffi-1.rs:29:9 | LL | foo(1); | ^^^--- argument #2 of type `u8` is missing | note: function defined here - --> $DIR/variadic-ffi-1.rs:16:8 + --> $DIR/variadic-ffi-1.rs:21:8 | LL | fn foo(f: isize, x: u8, ...); | ^^^ - @@ -37,7 +43,7 @@ LL | foo(1, /* u8 */); | ++++++++++ error[E0308]: mismatched types - --> $DIR/variadic-ffi-1.rs:26:56 + --> $DIR/variadic-ffi-1.rs:31:56 | LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; | ------------------------------------- ^^^ expected non-variadic fn, found variadic function @@ -48,7 +54,7 @@ LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; found fn item `unsafe extern "C" fn(_, _, ...) {foo}` error[E0308]: mismatched types - --> $DIR/variadic-ffi-1.rs:27:54 + --> $DIR/variadic-ffi-1.rs:32:54 | LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; | ----------------------------------- ^^^ expected variadic fn, found non-variadic function @@ -59,7 +65,7 @@ LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; found fn item `extern "C" fn(_, _) {bar}` error[E0617]: can't pass `f32` to variadic function - --> $DIR/variadic-ffi-1.rs:29:19 + --> $DIR/variadic-ffi-1.rs:34:19 | LL | foo(1, 2, 3f32); | ^^^^ @@ -70,7 +76,7 @@ LL | foo(1, 2, 3f32 as c_double); | +++++++++++ error[E0617]: can't pass `bool` to variadic function - --> $DIR/variadic-ffi-1.rs:30:19 + --> $DIR/variadic-ffi-1.rs:35:19 | LL | foo(1, 2, true); | ^^^^ @@ -81,7 +87,7 @@ LL | foo(1, 2, true as c_int); | ++++++++ error[E0617]: can't pass `i8` to variadic function - --> $DIR/variadic-ffi-1.rs:31:19 + --> $DIR/variadic-ffi-1.rs:36:19 | LL | foo(1, 2, 1i8); | ^^^ @@ -92,7 +98,7 @@ LL | foo(1, 2, 1i8 as c_int); | ++++++++ error[E0617]: can't pass `u8` to variadic function - --> $DIR/variadic-ffi-1.rs:32:19 + --> $DIR/variadic-ffi-1.rs:37:19 | LL | foo(1, 2, 1u8); | ^^^ @@ -103,7 +109,7 @@ LL | foo(1, 2, 1u8 as c_uint); | +++++++++ error[E0617]: can't pass `i16` to variadic function - --> $DIR/variadic-ffi-1.rs:33:19 + --> $DIR/variadic-ffi-1.rs:38:19 | LL | foo(1, 2, 1i16); | ^^^^ @@ -114,7 +120,7 @@ LL | foo(1, 2, 1i16 as c_int); | ++++++++ error[E0617]: can't pass `u16` to variadic function - --> $DIR/variadic-ffi-1.rs:34:19 + --> $DIR/variadic-ffi-1.rs:39:19 | LL | foo(1, 2, 1u16); | ^^^^ @@ -124,7 +130,7 @@ help: cast the value to `c_uint` LL | foo(1, 2, 1u16 as c_uint); | +++++++++ -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0045, E0060, E0308, E0617. For more information about an error, try `rustc --explain E0045`. diff --git a/tests/ui/c-variadic/variadic-ffi-2-arm.rs b/tests/ui/c-variadic/variadic-ffi-2-arm.rs deleted file mode 100644 index 3b0a71007a0..00000000000 --- a/tests/ui/c-variadic/variadic-ffi-2-arm.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ only-arm -//@ build-pass -#![feature(extended_varargs_abi_support)] - -fn aapcs(f: extern "aapcs" fn(usize, ...)) { - f(22, 44); -} - -fn main() {} diff --git a/tests/ui/c-variadic/variadic-ffi-2.rs b/tests/ui/c-variadic/variadic-ffi-2.rs deleted file mode 100644 index adfd9bfa279..00000000000 --- a/tests/ui/c-variadic/variadic-ffi-2.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![feature(extended_varargs_abi_support)] - -fn baz(f: extern "Rust" fn(usize, ...)) { - //~^ ERROR: C-variadic functions with the "Rust" calling convention are not supported - f(22, 44); -} - -#[cfg(target_arch = "x86_64")] -fn sysv(f: extern "sysv64" fn(usize, ...)) { - f(22, 44); -} -#[cfg(target_arch = "x86_64")] -fn win(f: extern "win64" fn(usize, ...)) { - f(22, 44); -} -#[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "x86", - target_arch = "x86_64" -))] -fn efiapi(f: extern "efiapi" fn(usize, ...)) { - f(22, 44); -} - -fn main() {} diff --git a/tests/ui/c-variadic/variadic-ffi-2.stderr b/tests/ui/c-variadic/variadic-ffi-2.stderr deleted file mode 100644 index 2ac0a9f5ea2..00000000000 --- a/tests/ui/c-variadic/variadic-ffi-2.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0045]: C-variadic functions with the "Rust" calling convention are not supported - --> $DIR/variadic-ffi-2.rs:3:11 - | -LL | fn baz(f: extern "Rust" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0045`. diff --git a/tests/ui/issues/issue-4333.rs b/tests/ui/cast/trait-object-cast-segfault-4333.rs index dccaa6f68bd..24e86d4d930 100644 --- a/tests/ui/issues/issue-4333.rs +++ b/tests/ui/cast/trait-object-cast-segfault-4333.rs @@ -7,3 +7,5 @@ pub fn main() { let stdout = &mut io::stdout() as &mut dyn io::Write; stdout.write(b"Hello!"); } + +// https://github.com/rust-lang/rust/issues/4333 diff --git a/tests/ui/cfg/cfg-panic-abort.rs b/tests/ui/cfg/cfg-panic-abort.rs index 448fde21086..b39888573b3 100644 --- a/tests/ui/cfg/cfg-panic-abort.rs +++ b/tests/ui/cfg/cfg-panic-abort.rs @@ -1,6 +1,7 @@ //@ build-pass //@ compile-flags: -C panic=abort //@ no-prefer-dynamic +//@ ignore-backends: gcc #[cfg(panic = "unwind")] pub fn bad() -> i32 { } diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/cfg/conditional-compilation-struct-11085.rs index c3f13199b30..cd6dded54d3 100644 --- a/tests/ui/issues/issue-11085.rs +++ b/tests/ui/cfg/conditional-compilation-struct-11085.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11085 + //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr index 394629c0001..057960ec014 100644 --- a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr @@ -26,6 +26,15 @@ LL | E::Number(_) if let E::String(s) = *value => { } ... LL | let x = value; | ^^^^^ value used here after move + | +note: if `E` implemented `Clone`, you could clone the value + --> $DIR/if-let-guards-errors.rs:32:1 + | +LL | E::Number(_) if let E::String(s) = *value => { } + | ------ you could clone this value +... +LL | enum E { + | ^^^^^^ consider implementing `Clone` for this type error: aborting due to 2 previous errors diff --git a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr index 5672845019b..4a6e3908827 100644 --- a/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr @@ -26,6 +26,15 @@ LL | E::Number(_) if let E::String(s) = *value => { } ... LL | let x = value; | ^^^^^ value used here after move + | +note: if `E` implemented `Clone`, you could clone the value + --> $DIR/if-let-guards-errors.rs:32:1 + | +LL | E::Number(_) if let E::String(s) = *value => { } + | ------ you could clone this value +... +LL | enum E { + | ^^^^^^ consider implementing `Clone` for this type error: aborting due to 2 previous errors diff --git a/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs b/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs index a4646d67c68..40d838b7e8e 100644 --- a/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs +++ b/tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs @@ -1,4 +1,6 @@ //@ run-pass +//@ ignore-backends: gcc + #![allow(dead_code)] // check that we don't have linear stack usage with multiple calls to `push` diff --git a/tests/ui/issues/issue-36278-prefix-nesting.rs b/tests/ui/codegen/dynamic-size-of-prefix-correctly-36278.rs index 3f2ca7a2460..78c0129faa1 100644 --- a/tests/ui/issues/issue-36278-prefix-nesting.rs +++ b/tests/ui/codegen/dynamic-size-of-prefix-correctly-36278.rs @@ -18,3 +18,5 @@ fn main() { size_of_unsized = mem::size_of_val::<Ack<_>>(&y); assert_eq!(size_of_sized, size_of_unsized); } + +// https://github.com/rust-lang/rust/issues/36278 diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs index d13fd4b63b3..53e29e75781 100644 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs index 5ec3c7cbdf5..47639762e7a 100644 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs index 97a875f15bc..70cbb9a52f7 100644 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs index 731c5b67882..694fb34828c 100644 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs index cdf07eade87..ade32663d48 100644 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs index 94739708ab8..d8feaeee4fa 100644 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs index b163c282d93..ad1d7b56c8c 100644 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs index b7824f53d77..a50369b46cb 100644 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs index 5f4ee731f7d..0b5b2df9f0e 100644 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs index 0f838af1fb1..1812a1163f0 100644 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs index fea41e03612..637f0042ada 100644 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs index 20ed991ed3d..5879b3f4f4f 100644 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs @@ -1,6 +1,7 @@ //@ known-bug: #107975 //@ compile-flags: -Copt-level=2 //@ run-pass +//@ ignore-backends: gcc // Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 diff --git a/tests/ui/issues/issue-11205.rs b/tests/ui/coercion/trait-object-arrays-11205.rs index 8530514f0ed..45d69dce323 100644 --- a/tests/ui/issues/issue-11205.rs +++ b/tests/ui/coercion/trait-object-arrays-11205.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11205 + //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/issues/issue-39211.rs b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.rs index ab86afc3410..b2566e54471 100644 --- a/tests/ui/issues/issue-39211.rs +++ b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.rs @@ -12,3 +12,5 @@ fn m<M: Mat>() { } fn main() { } + +// https://github.com/rust-lang/rust/issues/39211 diff --git a/tests/ui/issues/issue-39211.stderr b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.stderr index 2124bc667ff..2a80aff834a 100644 --- a/tests/ui/issues/issue-39211.stderr +++ b/tests/ui/const-generics/generic-parameter-in-const-expression-39211.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-39211.rs:9:17 + --> $DIR/generic-parameter-in-const-expression-39211.rs:9:17 | LL | let a = [3; M::Row::DIM]; | ^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let a = [3; M::Row::DIM]; = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-39211.rs:9:13 + --> $DIR/generic-parameter-in-const-expression-39211.rs:9:13 | LL | let a = [3; M::Row::DIM]; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/min_const_generics/macro-fail-const.rs b/tests/ui/const-generics/min_const_generics/macro-fail-const.rs new file mode 100644 index 00000000000..619d6de7ad2 --- /dev/null +++ b/tests/ui/const-generics/min_const_generics/macro-fail-const.rs @@ -0,0 +1,23 @@ +trait Marker<const N: usize> {} +struct Example<const N: usize>; +impl<const N: usize> Marker<N> for Example<N> {} + +fn make_marker() -> impl Marker<gimme_a_const!(marker)> { + //~^ ERROR: type provided when a constant was expected + //~| ERROR: type provided when a constant was expected + Example::<gimme_a_const!(marker)> + //~^ ERROR: type provided when a constant was expected +} + +fn main() { + let _ok = Example::<{ + #[macro_export] + macro_rules! gimme_a_const { + ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} + //~^ ERROR expected type + //~| ERROR expected type + } + gimme_a_const!(run) + }>; + let _ok = Example::<{gimme_a_const!(marker)}>; +} diff --git a/tests/ui/const-generics/min_const_generics/macro-fail-const.stderr b/tests/ui/const-generics/min_const_generics/macro-fail-const.stderr new file mode 100644 index 00000000000..2d8cb50834b --- /dev/null +++ b/tests/ui/const-generics/min_const_generics/macro-fail-const.stderr @@ -0,0 +1,51 @@ +error: expected type, found `{` + --> $DIR/macro-fail-const.rs:16:27 + | +LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> { + | ---------------------- + | | + | this macro call doesn't expand to a type + | in this macro invocation +... +LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} + | ^ expected type + | + = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected type, found `{` + --> $DIR/macro-fail-const.rs:16:27 + | +LL | Example::<gimme_a_const!(marker)> + | ---------------------- + | | + | this macro call doesn't expand to a type + | in this macro invocation +... +LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} + | ^ expected type + | + = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail-const.rs:5:33 + | +LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> { + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail-const.rs:5:33 + | +LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail-const.rs:8:13 + | +LL | Example::<gimme_a_const!(marker)> + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.rs b/tests/ui/const-generics/min_const_generics/macro-fail.rs index 8cfa5293cc2..ada9400b2a3 100644 --- a/tests/ui/const-generics/min_const_generics/macro-fail.rs +++ b/tests/ui/const-generics/min_const_generics/macro-fail.rs @@ -12,10 +12,7 @@ trait Marker<const N: usize> {} impl<const N: usize> Marker<N> for Example<N> {} fn make_marker() -> impl Marker<gimme_a_const!(marker)> { - //~^ ERROR: type provided when a constant was expected - //~| ERROR: type provided when a constant was expected Example::<gimme_a_const!(marker)> - //~^ ERROR: type provided when a constant was expected } fn from_marker(_: impl Marker<{ @@ -35,9 +32,7 @@ fn main() { }>; let _fail = Example::<external_macro!()>; - //~^ ERROR: type provided when a constant let _fail = Example::<gimme_a_const!()>; - //~^ ERROR unexpected end of macro invocation - //~| ERROR: type provided when a constant was expected + //~^ ERROR: unexpected end of macro invocation } diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.stderr b/tests/ui/const-generics/min_const_generics/macro-fail.stderr index 34764982bb0..b1d766cbfb6 100644 --- a/tests/ui/const-generics/min_const_generics/macro-fail.stderr +++ b/tests/ui/const-generics/min_const_generics/macro-fail.stderr @@ -1,5 +1,5 @@ error: expected type, found `{` - --> $DIR/macro-fail.rs:30:27 + --> $DIR/macro-fail.rs:27:27 | LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> { | ---------------------- @@ -13,7 +13,7 @@ LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: expected type, found `{` - --> $DIR/macro-fail.rs:30:27 + --> $DIR/macro-fail.rs:27:27 | LL | Example::<gimme_a_const!(marker)> | ---------------------- @@ -41,7 +41,7 @@ LL | let _fail = Example::<external_macro!()>; = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected end of macro invocation - --> $DIR/macro-fail.rs:40:25 + --> $DIR/macro-fail.rs:36:25 | LL | macro_rules! gimme_a_const { | -------------------------- when calling this macro @@ -50,43 +50,10 @@ LL | let _fail = Example::<gimme_a_const!()>; | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments | note: while trying to match meta-variable `$rusty:ident` - --> $DIR/macro-fail.rs:30:8 + --> $DIR/macro-fail.rs:27:8 | LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} | ^^^^^^^^^^^^^ -error[E0747]: type provided when a constant was expected - --> $DIR/macro-fail.rs:14:33 - | -LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> { - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0747]: type provided when a constant was expected - --> $DIR/macro-fail.rs:14:33 - | -LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0747]: type provided when a constant was expected - --> $DIR/macro-fail.rs:17:13 - | -LL | Example::<gimme_a_const!(marker)> - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0747]: type provided when a constant was expected - --> $DIR/macro-fail.rs:37:25 - | -LL | let _fail = Example::<external_macro!()>; - | ^^^^^^^^^^^^^^^^^ - -error[E0747]: type provided when a constant was expected - --> $DIR/macro-fail.rs:40:25 - | -LL | let _fail = Example::<gimme_a_const!()>; - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 9 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/consts/const-eval/parse_ints.rs b/tests/ui/consts/const-eval/parse_ints.rs index 409fae9e51d..6a7e157ea50 100644 --- a/tests/ui/consts/const-eval/parse_ints.rs +++ b/tests/ui/consts/const-eval/parse_ints.rs @@ -1,3 +1,5 @@ +//@ ignore-backends: gcc + const _OK: () = match i32::from_str_radix("-1234", 10) { Ok(x) => assert!(x == -1234), Err(_) => panic!(), diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr index 7e529c03725..9c9d083e7ca 100644 --- a/tests/ui/consts/const-eval/parse_ints.stderr +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` - --> $DIR/parse_ints.rs:5:24 + --> $DIR/parse_ints.rs:7:24 | LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_TOO_LOW` failed inside this call @@ -11,7 +11,7 @@ note: inside `core::num::<impl u64>::from_ascii_radix` = note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` - --> $DIR/parse_ints.rs:6:25 + --> $DIR/parse_ints.rs:8:25 | LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_TOO_HIGH` failed inside this call diff --git a/tests/ui/consts/const-unsized.rs b/tests/ui/consts/const-unsized.rs index e8af3323ceb..4140563fa40 100644 --- a/tests/ui/consts/const-unsized.rs +++ b/tests/ui/consts/const-unsized.rs @@ -10,14 +10,10 @@ const CONST_FOO: str = *"foo"; static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); //~^ ERROR the size for values of type -//~| ERROR cannot move out of a shared reference static STATIC_BAR: str = *"bar"; //~^ ERROR the size for values of type -//~| ERROR cannot move out of a shared reference fn main() { println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); - //~^ ERROR: cannot move a value of type `str` - //~| ERROR: cannot move a value of type `dyn Debug + Sync` } diff --git a/tests/ui/consts/const-unsized.stderr b/tests/ui/consts/const-unsized.stderr index c92fbc17f9c..a37a6df71f8 100644 --- a/tests/ui/consts/const-unsized.stderr +++ b/tests/ui/consts/const-unsized.stderr @@ -26,7 +26,7 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); = note: statics and constants must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/const-unsized.rs:15:1 + --> $DIR/const-unsized.rs:14:1 | LL | static STATIC_BAR: str = *"bar"; | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -46,31 +46,7 @@ error[E0507]: cannot move out of a shared reference LL | const CONST_FOO: str = *"foo"; | ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait -error[E0507]: cannot move out of a shared reference - --> $DIR/const-unsized.rs:11:37 - | -LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `dyn Debug + Sync`, which does not implement the `Copy` trait - -error[E0507]: cannot move out of a shared reference - --> $DIR/const-unsized.rs:15:26 - | -LL | static STATIC_BAR: str = *"bar"; - | ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait - -error[E0161]: cannot move a value of type `dyn Debug + Sync` - --> $DIR/const-unsized.rs:20:38 - | -LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); - | ^^^^^^^ the size of `dyn Debug + Sync` cannot be statically determined - -error[E0161]: cannot move a value of type `str` - --> $DIR/const-unsized.rs:20:48 - | -LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); - | ^^^^^^^^^ the size of `str` cannot be statically determined - -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0161, E0277, E0507. -For more information about an error, try `rustc --explain E0161`. +Some errors have detailed explanations: E0277, E0507. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index db2d50f4d22..8c21f7b1a5a 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ compile-flags: -Znext-solver #![feature(const_type_id, const_trait_impl, const_cmp)] diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 540eec5098b..05b94caef79 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const operator in constants - --> $DIR/const_cmp_type_id.rs:10:18 + --> $DIR/const_cmp_type_id.rs:11:18 | LL | let _a = TypeId::of::<u8>() < TypeId::of::<u16>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs index 5f364cd995e..f43823fa155 100644 --- a/tests/ui/consts/issue-73976-monomorphic.rs +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ check-pass // // This test is complement to the test in issue-73976-polymorphic.rs. diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 22791e7d15e..f2ddc928d12 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -1,3 +1,5 @@ +//@ ignore-backends: gcc + #![feature(const_trait_impl)] struct Foo<'a> { diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index 608ce0cfef0..d7664de5c07 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,17 +1,17 @@ error[E0277]: the trait bound `Vec<usize>: [const] Index<_>` is not satisfied - --> $DIR/issue-94675.rs:9:9 + --> $DIR/issue-94675.rs:11:9 | LL | self.bar[0] = baz.len(); | ^^^^^^^^^^^ error[E0277]: the trait bound `Vec<usize>: [const] IndexMut<usize>` is not satisfied - --> $DIR/issue-94675.rs:9:9 + --> $DIR/issue-94675.rs:11:9 | LL | self.bar[0] = baz.len(); | ^^^^^^^^^^^ error[E0277]: the trait bound `Vec<usize>: [const] Index<usize>` is not satisfied - --> $DIR/issue-94675.rs:9:9 + --> $DIR/issue-94675.rs:11:9 | LL | self.bar[0] = baz.len(); | ^^^^^^^^^^^ diff --git a/tests/ui/consts/issue-miri-1910.rs b/tests/ui/consts/issue-miri-1910.rs index 6eae885ea8a..78587bbb4dd 100644 --- a/tests/ui/consts/issue-miri-1910.rs +++ b/tests/ui/consts/issue-miri-1910.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ error-pattern unable to turn pointer into raw bytes //@ normalize-stderr: "alloc[0-9]+\+0x[a-z0-9]+" -> "ALLOC" diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr index 140b1861bb4..2b6e079e380 100644 --- a/tests/ui/consts/issue-miri-1910.stderr +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -1,5 +1,5 @@ error[E0080]: unable to turn pointer into integer - --> $DIR/issue-miri-1910.rs:7:5 + --> $DIR/issue-miri-1910.rs:8:5 | LL | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `C` failed here diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index 893dc321604..4f3f9aa6ada 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ compile-flags: -Z ui-testing=no use std::{ diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index de4acbffa28..0ac1e281107 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -1,11 +1,11 @@ error[E0080]: unable to copy parts of a pointer from memory at ALLOC0 - --> $DIR/missing_span_in_backtrace.rs:14:9 + --> $DIR/missing_span_in_backtrace.rs:15:9 | -14 | / ptr::swap_nonoverlapping( -15 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>, -16 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>, -17 | | mem::size_of::<&i32>(), -18 | | ); +15 | / ptr::swap_nonoverlapping( +16 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>, +17 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>, +18 | | mem::size_of::<&i32>(), +19 | | ); | |_________^ evaluation of `X` failed inside this call | = help: this code performed an operation that depends on the underlying bytes representing a pointer diff --git a/tests/ui/consts/try-operator.rs b/tests/ui/consts/try-operator.rs index 59d9fcb1cbd..cd0bf8ea571 100644 --- a/tests/ui/consts/try-operator.rs +++ b/tests/ui/consts/try-operator.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ run-pass #![feature(try_trait_v2)] diff --git a/tests/ui/coroutine/layout-error.rs b/tests/ui/coroutine/layout-error.rs index 6cf32134025..7f6714542c1 100644 --- a/tests/ui/coroutine/layout-error.rs +++ b/tests/ui/coroutine/layout-error.rs @@ -17,6 +17,7 @@ impl<F: Future> Task<F> { } pub type F = impl Future; + #[define_opaque(F)] fn foo() where diff --git a/tests/ui/coroutine/layout-error.stderr b/tests/ui/coroutine/layout-error.stderr index 91e35216435..f3b3843de89 100644 --- a/tests/ui/coroutine/layout-error.stderr +++ b/tests/ui/coroutine/layout-error.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `Foo` in this scope - --> $DIR/layout-error.rs:26:17 + --> $DIR/layout-error.rs:27:17 | LL | let a = Foo; | ^^^ not found in this scope diff --git a/tests/ui/coroutine/panic-drops-resume.rs b/tests/ui/coroutine/panic-drops-resume.rs index b23666b7885..ee58dab3e37 100644 --- a/tests/ui/coroutine/panic-drops-resume.rs +++ b/tests/ui/coroutine/panic-drops-resume.rs @@ -2,6 +2,7 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] diff --git a/tests/ui/coroutine/panic-drops.rs b/tests/ui/coroutine/panic-drops.rs index 8c2cf560f2a..c8ac401372f 100644 --- a/tests/ui/coroutine/panic-drops.rs +++ b/tests/ui/coroutine/panic-drops.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] diff --git a/tests/ui/coroutine/panic-safe.rs b/tests/ui/coroutine/panic-safe.rs index 6b9b4cb33c3..cee2afacb61 100644 --- a/tests/ui/coroutine/panic-safe.rs +++ b/tests/ui/coroutine/panic-safe.rs @@ -1,6 +1,6 @@ //@ run-pass //@ needs-unwind - +//@ ignore-backends: gcc #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] diff --git a/tests/ui/coroutine/resume-after-return.rs b/tests/ui/coroutine/resume-after-return.rs index 7028e1e81e5..f566bd37d3d 100644 --- a/tests/ui/coroutine/resume-after-return.rs +++ b/tests/ui/coroutine/resume-after-return.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ run-pass //@ needs-unwind diff --git a/tests/ui/coroutine/unwind-abort-mix.rs b/tests/ui/coroutine/unwind-abort-mix.rs index 517c6613e3d..175c2928a80 100644 --- a/tests/ui/coroutine/unwind-abort-mix.rs +++ b/tests/ui/coroutine/unwind-abort-mix.rs @@ -6,6 +6,7 @@ //@ aux-build:unwind-aux.rs //@ compile-flags: -Cpanic=abort //@ needs-unwind +//@ ignore-backends: gcc extern crate unwind_aux; pub fn main() { diff --git a/tests/ui/issues/auxiliary/issue-2472-b.rs b/tests/ui/cross-crate/auxiliary/exporting-impl-from-root-causes-ice-2472-b.rs index 0d151520fe0..0d151520fe0 100644 --- a/tests/ui/issues/auxiliary/issue-2472-b.rs +++ b/tests/ui/cross-crate/auxiliary/exporting-impl-from-root-causes-ice-2472-b.rs diff --git a/tests/ui/cross-crate/exporting-impl-from-root-causes-ice-2472.rs b/tests/ui/cross-crate/exporting-impl-from-root-causes-ice-2472.rs new file mode 100644 index 00000000000..86d637b579d --- /dev/null +++ b/tests/ui/cross-crate/exporting-impl-from-root-causes-ice-2472.rs @@ -0,0 +1,15 @@ +//@ run-pass +//@ aux-build:exporting-impl-from-root-causes-ice-2472-b.rs + + +extern crate exporting_impl_from_root_causes_ice_2472_b as lib; + +use lib::{S, T}; + +pub fn main() { + let s = S(()); + s.foo(); + s.bar(); +} + +// https://github.com/rust-lang/rust/issues/2472 diff --git a/tests/ui/delegation/fn-header.rs b/tests/ui/delegation/fn-header.rs index 9de0d549f20..608aef8d968 100644 --- a/tests/ui/delegation/fn-header.rs +++ b/tests/ui/delegation/fn-header.rs @@ -1,6 +1,7 @@ //@ check-pass //@ edition:2018 //@ aux-crate:fn_header_aux=fn-header-aux.rs +//@ ignore-backends: gcc #![feature(c_variadic)] #![feature(fn_delegation)] diff --git a/tests/ui/issues/issue-34229.rs b/tests/ui/derives/invalid-derive-comparison-34229.rs index 13e627a492f..d77ca78dc81 100644 --- a/tests/ui/issues/issue-34229.rs +++ b/tests/ui/derives/invalid-derive-comparison-34229.rs @@ -3,3 +3,5 @@ //~^ ERROR can't compare `Comparable` fn main() {} + +// https://github.com/rust-lang/rust/issues/34229 diff --git a/tests/ui/issues/issue-34229.stderr b/tests/ui/derives/invalid-derive-comparison-34229.stderr index 2385284de0b..e3a9970670e 100644 --- a/tests/ui/issues/issue-34229.stderr +++ b/tests/ui/derives/invalid-derive-comparison-34229.stderr @@ -1,5 +1,5 @@ error[E0277]: can't compare `Comparable` with `Comparable` - --> $DIR/issue-34229.rs:2:46 + --> $DIR/invalid-derive-comparison-34229.rs:2:46 | LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ---------- ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` diff --git a/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs new file mode 100644 index 00000000000..f2965778431 --- /dev/null +++ b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs @@ -0,0 +1,24 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/106755 + +//@ compile-flags:-Ztranslate-lang=en_US + +#![feature(negative_impls)] +#![feature(marker_trait_attr)] + +#[marker] +trait MyTrait {} + +struct TestType<T>(::std::marker::PhantomData<T>); + +unsafe impl<T: MyTrait + 'static> Send for TestType<T> {} + +impl<T: MyTrait> !Send for TestType<T> {} +//~^ ERROR found both positive and negative implementation +//~| ERROR `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not + +unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations + +impl !Send for TestType<i32> {} +//~^ ERROR `!Send` impls cannot be specialized + +fn main() {} diff --git a/tests/ui/issues/issue-106755.stderr b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr index da6b8c5c563..1dc31e161a7 100644 --- a/tests/ui/issues/issue-106755.stderr +++ b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr @@ -1,5 +1,5 @@ error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`: - --> $DIR/issue-106755.rs:13:1 + --> $DIR/primary-fluent-bundle-missing.rs:15:1 | LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {} | ------------------------------------------------------ positive implementation here @@ -8,7 +8,7 @@ LL | impl<T: MyTrait> !Send for TestType<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>` - --> $DIR/issue-106755.rs:17:1 + --> $DIR/primary-fluent-bundle-missing.rs:19:1 | LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {} | ------------------------------------------------------ first implementation here @@ -17,26 +17,26 @@ LL | unsafe impl<T: 'static> Send for TestType<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not - --> $DIR/issue-106755.rs:13:9 + --> $DIR/primary-fluent-bundle-missing.rs:15:9 | LL | impl<T: MyTrait> !Send for TestType<T> {} | ^^^^^^^ | note: the implementor must specify the same requirement - --> $DIR/issue-106755.rs:9:1 + --> $DIR/primary-fluent-bundle-missing.rs:11:1 | LL | struct TestType<T>(::std::marker::PhantomData<T>); | ^^^^^^^^^^^^^^^^^^ error[E0366]: `!Send` impls cannot be specialized - --> $DIR/issue-106755.rs:19:1 + --> $DIR/primary-fluent-bundle-missing.rs:21:1 | LL | impl !Send for TestType<i32> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `i32` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/issue-106755.rs:9:1 + --> $DIR/primary-fluent-bundle-missing.rs:11:1 | LL | struct TestType<T>(::std::marker::PhantomData<T>); | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/issues/issue-10734.rs b/tests/ui/drop/conditional-drop-10734.rs index 6d815aeca07..25f492bf9e0 100644 --- a/tests/ui/issues/issue-10734.rs +++ b/tests/ui/drop/conditional-drop-10734.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10734 + //@ run-pass #![allow(non_upper_case_globals)] diff --git a/tests/ui/issues/issue-9446.rs b/tests/ui/drop/drop-immediate-non-box-ty-9446.rs index a6ea91e8785..ad3f7b64aa9 100644 --- a/tests/ui/issues/issue-9446.rs +++ b/tests/ui/drop/drop-immediate-non-box-ty-9446.rs @@ -28,3 +28,5 @@ pub fn main() { Wrapper::new("Bob".to_string()).say_hi(); } } + +// https://github.com/rust-lang/rust/issues/9446 diff --git a/tests/ui/drop/dynamic-drop-async.rs b/tests/ui/drop/dynamic-drop-async.rs index e7a32d3c24e..64de6995c7a 100644 --- a/tests/ui/drop/dynamic-drop-async.rs +++ b/tests/ui/drop/dynamic-drop-async.rs @@ -6,6 +6,7 @@ //@ run-pass //@ needs-unwind //@ edition:2018 +//@ ignore-backends: gcc #![allow(unused)] diff --git a/tests/ui/drop/dynamic-drop.rs b/tests/ui/drop/dynamic-drop.rs index b695b5702d9..1bd75e1852c 100644 --- a/tests/ui/drop/dynamic-drop.rs +++ b/tests/ui/drop/dynamic-drop.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![feature(if_let_guard)] diff --git a/tests/ui/issues/issue-10802.rs b/tests/ui/drop/trait-object-drop-10802.rs index eca701ce98c..a8a955ad833 100644 --- a/tests/ui/issues/issue-10802.rs +++ b/tests/ui/drop/trait-object-drop-10802.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10802 + //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/dyn-compatibility/taint-const-eval.rs b/tests/ui/dyn-compatibility/taint-const-eval.rs index a5c01e1791e..3d1b3b8fe61 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.rs +++ b/tests/ui/dyn-compatibility/taint-const-eval.rs @@ -6,6 +6,5 @@ trait Qux { static FOO: &(dyn Qux + Sync) = "desc"; //~^ ERROR the trait `Qux` is not dyn compatible -//~| ERROR the trait `Qux` is not dyn compatible fn main() {} diff --git a/tests/ui/dyn-compatibility/taint-const-eval.stderr b/tests/ui/dyn-compatibility/taint-const-eval.stderr index 585c1f012c7..e4be9870fdc 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.stderr +++ b/tests/ui/dyn-compatibility/taint-const-eval.stderr @@ -21,30 +21,6 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o LL | fn bar() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qux` is not dyn compatible - --> $DIR/taint-const-eval.rs:7:15 - | -LL | static FOO: &(dyn Qux + Sync) = "desc"; - | ^^^^^^^^^^^^^^ `Qux` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> - --> $DIR/taint-const-eval.rs:4:8 - | -LL | trait Qux { - | --- this trait is not dyn compatible... -LL | fn bar(); - | ^^^ ...because associated function `bar` has no `self` parameter - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider turning `bar` into a method by giving it a `&self` argument - | -LL | fn bar(&self); - | +++++ -help: alternatively, consider constraining `bar` so it does not apply to trait objects - | -LL | fn bar() where Self: Sized; - | +++++++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs index f8d2755b9d7..df473946317 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs @@ -26,7 +26,7 @@ pub fn check_async() { module::async(); //~ ERROR expected identifier, found keyword `async` module::r#async(); // OK - let _recovery_witness: () = 0; //~ ERROR mismatched types + let _recovery_witness: () = 0; // not emitted because of the macro parsing error } //~? ERROR macro expansion ends with an incomplete expression diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 34f5c7d3084..4d69df9fff8 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -61,14 +61,5 @@ error: macro expansion ends with an incomplete expression: expected one of `move LL | if passes_tt!(async) == 1 {} | ^ expected one of `move`, `use`, `{`, `|`, or `||` -error[E0308]: mismatched types - --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33 - | -LL | let _recovery_witness: () = 0; - | -- ^ expected `()`, found integer - | | - | expected due to this - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs index f4438472a0e..34aaf16b4ae 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs @@ -36,8 +36,6 @@ pub fn check_async() { if local_passes_tt!(r#async) == 1 {} // OK module::async(); //~ ERROR expected identifier, found keyword `async` module::r#async(); // OK - - let _recovery_witness: () = 0; //~ ERROR mismatched types } //~? ERROR macro expansion ends with an incomplete expression diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index dd3f4938c74..753dac605a3 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -73,14 +73,5 @@ error: macro expansion ends with an incomplete expression: expected one of `move LL | if local_passes_tt!(async) == 1 {} | ^ expected one of `move`, `use`, `{`, `|`, or `||` -error[E0308]: mismatched types - --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33 - | -LL | let _recovery_witness: () = 0; - | -- ^ expected `()`, found integer - | | - | expected due to this - -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-32326.rs b/tests/ui/enum/recursive-enum-memory-32326.rs index e928c66e2cc..6b8b04a7c91 100644 --- a/tests/ui/issues/issue-32326.rs +++ b/tests/ui/enum/recursive-enum-memory-32326.rs @@ -8,3 +8,5 @@ enum Expr { //~ ERROR E0072 } fn main() { } + +// https://github.com/rust-lang/rust/issues/32326 diff --git a/tests/ui/issues/issue-32326.stderr b/tests/ui/enum/recursive-enum-memory-32326.stderr index 1989a915cc1..0260a6758ed 100644 --- a/tests/ui/issues/issue-32326.stderr +++ b/tests/ui/enum/recursive-enum-memory-32326.stderr @@ -1,5 +1,5 @@ error[E0072]: recursive type `Expr` has infinite size - --> $DIR/issue-32326.rs:5:1 + --> $DIR/recursive-enum-memory-32326.rs:5:1 | LL | enum Expr { | ^^^^^^^^^ diff --git a/tests/ui/issues/issue-10764.rs b/tests/ui/extern/extern-rust-fn-type-error-10764.rs index bb915f58d9d..f172f6e6b7d 100644 --- a/tests/ui/issues/issue-10764.rs +++ b/tests/ui/extern/extern-rust-fn-type-error-10764.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10764 + fn f(_: extern "Rust" fn()) {} extern "C" fn bar() {} diff --git a/tests/ui/issues/issue-10764.stderr b/tests/ui/extern/extern-rust-fn-type-error-10764.stderr index f3bd0100a72..fa72d7dd6b2 100644 --- a/tests/ui/issues/issue-10764.stderr +++ b/tests/ui/extern/extern-rust-fn-type-error-10764.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-10764.rs:4:15 + --> $DIR/extern-rust-fn-type-error-10764.rs:6:15 | LL | fn main() { f(bar) } | - ^^^ expected "Rust" fn, found "C" fn @@ -9,7 +9,7 @@ LL | fn main() { f(bar) } = note: expected fn pointer `fn()` found fn item `extern "C" fn() {bar}` note: function defined here - --> $DIR/issue-10764.rs:1:4 + --> $DIR/extern-rust-fn-type-error-10764.rs:3:4 | LL | fn f(_: extern "Rust" fn()) {} | ^ --------------------- diff --git a/tests/ui/issues/issue-10877.rs b/tests/ui/extern/foreign-fn-pattern-error-10877.rs index 15a383175b9..9a047d4f34e 100644 --- a/tests/ui/issues/issue-10877.rs +++ b/tests/ui/extern/foreign-fn-pattern-error-10877.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10877 + struct Foo { x: isize, } diff --git a/tests/ui/issues/issue-10877.stderr b/tests/ui/extern/foreign-fn-pattern-error-10877.stderr index bd3797cba55..cab7b6ab06b 100644 --- a/tests/ui/issues/issue-10877.stderr +++ b/tests/ui/extern/foreign-fn-pattern-error-10877.stderr @@ -1,23 +1,23 @@ error[E0130]: patterns aren't allowed in foreign function declarations - --> $DIR/issue-10877.rs:5:12 + --> $DIR/foreign-fn-pattern-error-10877.rs:7:12 | LL | fn foo(1: ()); | ^ pattern not allowed in foreign function error[E0130]: patterns aren't allowed in foreign function declarations - --> $DIR/issue-10877.rs:7:12 + --> $DIR/foreign-fn-pattern-error-10877.rs:9:12 | LL | fn bar((): isize); | ^^ pattern not allowed in foreign function error[E0130]: patterns aren't allowed in foreign function declarations - --> $DIR/issue-10877.rs:9:12 + --> $DIR/foreign-fn-pattern-error-10877.rs:11:12 | LL | fn baz(Foo { x }: isize); | ^^^^^^^^^ pattern not allowed in foreign function error[E0130]: patterns aren't allowed in foreign function declarations - --> $DIR/issue-10877.rs:11:12 + --> $DIR/foreign-fn-pattern-error-10877.rs:13:12 | LL | fn qux((x, y): ()); | ^^^^^^ pattern not allowed in foreign function diff --git a/tests/ui/extern/issue-36122-accessing-externed-dst.rs b/tests/ui/extern/issue-36122-accessing-externed-dst.rs index 9fb7780e3d7..5f886ff5737 100644 --- a/tests/ui/extern/issue-36122-accessing-externed-dst.rs +++ b/tests/ui/extern/issue-36122-accessing-externed-dst.rs @@ -3,5 +3,4 @@ fn main() { static symbol: [usize]; //~ ERROR: the size for values of type } println!("{}", symbol[0]); - //~^ ERROR: extern static is unsafe } diff --git a/tests/ui/extern/issue-36122-accessing-externed-dst.stderr b/tests/ui/extern/issue-36122-accessing-externed-dst.stderr index 8007c3f13e5..c617cf4e61b 100644 --- a/tests/ui/extern/issue-36122-accessing-externed-dst.stderr +++ b/tests/ui/extern/issue-36122-accessing-externed-dst.stderr @@ -7,15 +7,6 @@ LL | static symbol: [usize]; = help: the trait `Sized` is not implemented for `[usize]` = note: statics and constants must have a statically known size -error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-36122-accessing-externed-dst.rs:5:20 - | -LL | println!("{}", symbol[0]); - | ^^^^^^ use of extern static - | - = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0133, E0277. -For more information about an error, try `rustc --explain E0133`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 9740eaaf1e9..b93cb2ea006 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -57,7 +57,7 @@ // see gated-link-args.rs // see issue-43106-gating-of-macro_escape.rs for crate-level; but non crate-level is below at "2700" // (cannot easily test gating of crate-level #[no_std]; but non crate-level is below at "2600") -#![proc_macro_derive()] //~ WARN `#[proc_macro_derive]` only has an effect +#![proc_macro_derive(Test)] //~ WARN `#[proc_macro_derive]` only has an effect #![doc = "2400"] #![cold] //~ WARN attribute should be applied to a function //~^ WARN this was previously accepted diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 9016ca1efa7..8bac1f6155e 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -367,12 +367,6 @@ warning: `#[should_panic]` only has an effect on functions LL | #![should_panic] | ^^^^^^^^^^^^^^^^ -warning: `#[proc_macro_derive]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 - | -LL | #![proc_macro_derive()] - | ^^^^^^^^^^^^^^^^^^^^^^^ - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | @@ -409,6 +403,12 @@ warning: `#[must_use]` has no effect when applied to a module LL | #![must_use] | ^^^^^^^^^^^^ +warning: `#[proc_macro_derive]` only has an effect on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 + | +LL | #![proc_macro_derive(Test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs index a94ffd602ef..392880e1b3b 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs @@ -7,27 +7,27 @@ // signal errors, making it incompatible with the "warnings only" // nature of issue-43106-gating-of-builtin-attrs.rs -#[proc_macro_derive()] +#[proc_macro_derive(Test)] //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions mod proc_macro_derive1 { - mod inner { #![proc_macro_derive()] } + mod inner { #![proc_macro_derive(Test)] } // (no error issued here if there was one on outer module) } mod proc_macro_derive2 { - mod inner { #![proc_macro_derive()] } + mod inner { #![proc_macro_derive(Test)] } //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions - #[proc_macro_derive()] fn f() { } + #[proc_macro_derive(Test)] fn f() { } //~^ ERROR the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` - #[proc_macro_derive()] struct S; + #[proc_macro_derive(Test)] struct S; //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions - #[proc_macro_derive()] type T = S; + #[proc_macro_derive(Test)] type T = S; //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions - #[proc_macro_derive()] impl S { } + #[proc_macro_derive(Test)] impl S { } //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr index e202b472d9c..537032d777f 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr @@ -1,38 +1,38 @@ error: the `#[proc_macro_derive]` attribute may only be used on bare functions --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:10:1 | -LL | #[proc_macro_derive()] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(Test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute may only be used on bare functions --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:18:17 | -LL | mod inner { #![proc_macro_derive()] } - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | mod inner { #![proc_macro_derive(Test)] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:21:5 | -LL | #[proc_macro_derive()] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(Test)] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute may only be used on bare functions --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:24:5 | -LL | #[proc_macro_derive()] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(Test)] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute may only be used on bare functions --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:27:5 | -LL | #[proc_macro_derive()] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(Test)] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute may only be used on bare functions --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:30:5 | -LL | #[proc_macro_derive()] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(Test)] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/float/target-has-reliable-nightly-float.rs b/tests/ui/float/target-has-reliable-nightly-float.rs index ad8600fc635..399f101f49a 100644 --- a/tests/ui/float/target-has-reliable-nightly-float.rs +++ b/tests/ui/float/target-has-reliable-nightly-float.rs @@ -19,8 +19,10 @@ pub fn has_f128() {} pub fn has_f128_math() {} fn main() { - if cfg!(target_arch = "aarch64") && cfg!(target_os = "linux") { - // Aarch64+Linux is one target that has support for all features, so use it to spot + if cfg!(target_arch = "aarch64") && + cfg!(target_os = "linux") && + cfg!(not(target_env = "musl")) { + // Aarch64+GNU+Linux is one target that has support for all features, so use it to spot // check that the compiler does indeed enable these gates. assert!(cfg!(target_has_reliable_f16)); diff --git a/tests/ui/issues/auxiliary/issue-18514.rs b/tests/ui/generics/auxiliary/generic-impl-method-match-autoderef-18514.rs index 20c8e60ee45..20c8e60ee45 100644 --- a/tests/ui/issues/auxiliary/issue-18514.rs +++ b/tests/ui/generics/auxiliary/generic-impl-method-match-autoderef-18514.rs diff --git a/tests/ui/issues/issue-18514.rs b/tests/ui/generics/generic-impl-method-match-autoderef-18514.rs index 89f58d3988d..3520e936209 100644 --- a/tests/ui/issues/issue-18514.rs +++ b/tests/ui/generics/generic-impl-method-match-autoderef-18514.rs @@ -5,12 +5,14 @@ // expression that autoderefs through an overloaded generic deref // impl. -//@ aux-build:issue-18514.rs +//@ aux-build:generic-impl-method-match-autoderef-18514.rs -extern crate issue_18514 as ice; +extern crate generic_impl_method_match_autoderef_18514 as ice; use ice::{Tr, St}; fn main() { let st: St<()> = St(vec![]); st.tr(); } + +// https://github.com/rust-lang/rust/issues/18514 diff --git a/tests/ui/issues/issue-10806.rs b/tests/ui/imports/use-declaration-no-path-segment-prefix.rs index 31315dc7c93..f7fbc084ebf 100644 --- a/tests/ui/issues/issue-10806.rs +++ b/tests/ui/imports/use-declaration-no-path-segment-prefix.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10806 + //@ edition: 2015 //@ run-pass #![allow(unused_imports)] diff --git a/tests/ui/issues/issue-10718.rs b/tests/ui/inference/fnonce-closure-call.rs index 68ac0bbe49f..262a193609f 100644 --- a/tests/ui/issues/issue-10718.rs +++ b/tests/ui/inference/fnonce-closure-call.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10718 + //@ run-pass fn f<F:FnOnce()>(p: F) { diff --git a/tests/ui/issues/issue-10436.rs b/tests/ui/inference/generic-type-inference-10436.rs index 672aa2464dc..456a9b86c34 100644 --- a/tests/ui/issues/issue-10436.rs +++ b/tests/ui/inference/generic-type-inference-10436.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10436 + //@ run-pass fn works<T>(x: T) -> Vec<T> { vec![x] } diff --git a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs index 346a94c37dd..cdf8aa85482 100644 --- a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -4,6 +4,7 @@ //@ revisions: default strict //@ [strict]compile-flags: -Zstrict-init-checks //@ needs-subprocess +//@ ignore-backends: gcc #![allow(deprecated, invalid_value)] #![feature(never_type)] diff --git a/tests/ui/issues/issue-10767.rs b/tests/ui/issues/issue-10767.rs deleted file mode 100644 index 2060d15b4c7..00000000000 --- a/tests/ui/issues/issue-10767.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -pub fn main() { - fn f() { - } - let _: Box<fn()> = Box::new(f as fn()); -} diff --git a/tests/ui/issues/issue-14875.rs b/tests/ui/issues/issue-14875.rs index 235d255716f..e330c64a335 100644 --- a/tests/ui/issues/issue-14875.rs +++ b/tests/ui/issues/issue-14875.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc // Check that values are not leaked when a dtor panics (#14875) diff --git a/tests/ui/issues/issue-2472.rs b/tests/ui/issues/issue-2472.rs deleted file mode 100644 index f8f539ed1d1..00000000000 --- a/tests/ui/issues/issue-2472.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -//@ aux-build:issue-2472-b.rs - - -extern crate issue_2472_b; - -use issue_2472_b::{S, T}; - -pub fn main() { - let s = S(()); - s.foo(); - s.bar(); -} diff --git a/tests/ui/issues/issue-29948.rs b/tests/ui/issues/issue-29948.rs index 77e1f6807d9..77a3885da04 100644 --- a/tests/ui/issues/issue-29948.rs +++ b/tests/ui/issues/issue-29948.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc use std::panic; diff --git a/tests/ui/issues/issue-49544.rs b/tests/ui/issues/issue-49544.rs deleted file mode 100644 index bb052501f8b..00000000000 --- a/tests/ui/issues/issue-49544.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ aux-build:issue-49544.rs -//@ check-pass - -extern crate issue_49544; -use issue_49544::foo; - -fn main() { - let _ = foo(); -} diff --git a/tests/ui/issues/auxiliary/issue-49544.rs b/tests/ui/iterators/auxiliary/iterator-adapter-undeclared-type-49544.rs index f8b3a3fba1e..f8b3a3fba1e 100644 --- a/tests/ui/issues/auxiliary/issue-49544.rs +++ b/tests/ui/iterators/auxiliary/iterator-adapter-undeclared-type-49544.rs diff --git a/tests/ui/iterators/iter-sum-overflow-debug.rs b/tests/ui/iterators/iter-sum-overflow-debug.rs index 32efc925a45..974282b0379 100644 --- a/tests/ui/iterators/iter-sum-overflow-debug.rs +++ b/tests/ui/iterators/iter-sum-overflow-debug.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc //@ compile-flags: -C debug_assertions=yes use std::panic; diff --git a/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs b/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs index 8fffd19e2be..aba6f9a188f 100644 --- a/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs +++ b/tests/ui/iterators/iter-sum-overflow-overflow-checks.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc //@ compile-flags: -C overflow-checks use std::panic; diff --git a/tests/ui/iterators/iterator-adapter-undeclared-type-49544.rs b/tests/ui/iterators/iterator-adapter-undeclared-type-49544.rs new file mode 100644 index 00000000000..f2532ceb1ba --- /dev/null +++ b/tests/ui/iterators/iterator-adapter-undeclared-type-49544.rs @@ -0,0 +1,11 @@ +//@ aux-build:iterator-adapter-undeclared-type-49544.rs +//@ check-pass + +extern crate iterator_adapter_undeclared_type_49544 as lib; +use lib::foo; + +fn main() { + let _ = foo(); +} + +// https://github.com/rust-lang/rust/issues/49544 diff --git a/tests/ui/layout/issue-84108.rs b/tests/ui/layout/issue-84108.rs index 974d5310f6b..33884617acb 100644 --- a/tests/ui/layout/issue-84108.rs +++ b/tests/ui/layout/issue-84108.rs @@ -14,5 +14,3 @@ const BAR: (&Path, [u8], usize) = ("hello", [], 42); static BAZ: ([u8], usize) = ([], 0); //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time -//~| ERROR the size for values of type `[u8]` cannot be known at compilation time -//~| ERROR mismatched types diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr index e296abfc3b5..62a6ae341fa 100644 --- a/tests/ui/layout/issue-84108.stderr +++ b/tests/ui/layout/issue-84108.stderr @@ -57,26 +57,7 @@ LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); = note: expected slice `[u8]` found array `[_; 0]` -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/issue-84108.rs:15:13 - | -LL | static BAZ: ([u8], usize) = ([], 0); - | ^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` - = note: only the last element of a tuple may have a dynamically sized type - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0308]: mismatched types - --> $DIR/issue-84108.rs:15:30 - | -LL | static BAZ: ([u8], usize) = ([], 0); - | ^^ expected `[u8]`, found `[_; 0]` - | - = note: expected slice `[u8]` - found array `[_; 0]` - -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0277, E0308, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-10396.rs b/tests/ui/lifetimes/array-pattern-matching-10396.rs index 082216d557c..5fc141bc460 100644 --- a/tests/ui/issues/issue-10396.rs +++ b/tests/ui/lifetimes/array-pattern-matching-10396.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10396 + //@ check-pass #![allow(dead_code)] #[derive(Debug)] diff --git a/tests/ui/issues/issue-10291.rs b/tests/ui/lifetimes/closure-lifetime-bounds-10291.rs index 31b9e124046..42dc6c2cafa 100644 --- a/tests/ui/issues/issue-10291.rs +++ b/tests/ui/lifetimes/closure-lifetime-bounds-10291.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10291 + fn test<'x>(x: &'x isize) { drop::<Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { x diff --git a/tests/ui/issues/issue-10291.stderr b/tests/ui/lifetimes/closure-lifetime-bounds-10291.stderr index 68ed9a0de5d..34f8ca40871 100644 --- a/tests/ui/issues/issue-10291.stderr +++ b/tests/ui/lifetimes/closure-lifetime-bounds-10291.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-10291.rs:3:9 + --> $DIR/closure-lifetime-bounds-10291.rs:5:9 | LL | fn test<'x>(x: &'x isize) { | -- lifetime `'x` defined here diff --git a/tests/ui/issues/issue-11374.rs b/tests/ui/lifetimes/container-lifetime-error-11374.rs index 60ee256c65a..59d13d04e46 100644 --- a/tests/ui/issues/issue-11374.rs +++ b/tests/ui/lifetimes/container-lifetime-error-11374.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11374 + use std::io::{self, Read}; use std::vec; diff --git a/tests/ui/issues/issue-11374.stderr b/tests/ui/lifetimes/container-lifetime-error-11374.stderr index 3ae5cfc79f8..a29b5ae137c 100644 --- a/tests/ui/issues/issue-11374.stderr +++ b/tests/ui/lifetimes/container-lifetime-error-11374.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-11374.rs:27:15 + --> $DIR/container-lifetime-error-11374.rs:29:15 | LL | c.read_to(v); | ------- ^ expected `&mut [u8]`, found `Vec<_>` @@ -9,7 +9,7 @@ LL | c.read_to(v); = note: expected mutable reference `&mut [u8]` found struct `Vec<_>` note: method defined here - --> $DIR/issue-11374.rs:13:12 + --> $DIR/container-lifetime-error-11374.rs:15:12 | LL | pub fn read_to(&mut self, vec: &mut [u8]) { | ^^^^^^^ -------------- @@ -19,7 +19,7 @@ LL | c.read_to(&mut v); | ++++ error[E0515]: cannot return value referencing local variable `r` - --> $DIR/issue-11374.rs:20:5 + --> $DIR/container-lifetime-error-11374.rs:22:5 | LL | Container::wrap(&mut r as &mut dyn io::Read) | ^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/issues/issue-10228.rs b/tests/ui/lifetimes/enum-lifetime-container-10228.rs index a59ccf926f9..ebbefb619c6 100644 --- a/tests/ui/issues/issue-10228.rs +++ b/tests/ui/lifetimes/enum-lifetime-container-10228.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10228 + //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/issues/issue-10412.rs b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.rs index 68ce0c2ea3c..a5b303df2fd 100644 --- a/tests/ui/issues/issue-10412.rs +++ b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10412 + trait Serializable<'self, T> { //~^ ERROR lifetimes cannot use keyword names fn serialize(val: &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names diff --git a/tests/ui/issues/issue-10412.stderr b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.stderr index c74ba1306cc..236bdf1ac85 100644 --- a/tests/ui/issues/issue-10412.stderr +++ b/tests/ui/lifetimes/keyword-self-lifetime-error-10412.stderr @@ -1,47 +1,47 @@ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:1:20 + --> $DIR/keyword-self-lifetime-error-10412.rs:3:20 | LL | trait Serializable<'self, T> { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:3:24 + --> $DIR/keyword-self-lifetime-error-10412.rs:5:24 | LL | fn serialize(val: &'self T) -> Vec<u8>; | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:4:37 + --> $DIR/keyword-self-lifetime-error-10412.rs:6:37 | LL | fn deserialize(repr: &[u8]) -> &'self T; | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:7:6 + --> $DIR/keyword-self-lifetime-error-10412.rs:9:6 | LL | impl<'self> Serializable<str> for &'self str { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:7:36 + --> $DIR/keyword-self-lifetime-error-10412.rs:9:36 | LL | impl<'self> Serializable<str> for &'self str { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:11:24 + --> $DIR/keyword-self-lifetime-error-10412.rs:13:24 | LL | fn serialize(val: &'self str) -> Vec<u8> { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:15:37 + --> $DIR/keyword-self-lifetime-error-10412.rs:17:37 | LL | fn deserialize(repr: &[u8]) -> &'self str { | ^^^^^ error[E0726]: implicit elided lifetime not allowed here - --> $DIR/issue-10412.rs:7:13 + --> $DIR/keyword-self-lifetime-error-10412.rs:9:13 | LL | impl<'self> Serializable<str> for &'self str { | ^^^^^^^^^^^^^^^^^ expected lifetime parameter diff --git a/tests/ui/issues/issue-10902.rs b/tests/ui/lifetimes/tuple-struct-vs-struct-with-fields-borrowck-10902.rs index 7cdf8808aa0..97c0d0bf554 100644 --- a/tests/ui/issues/issue-10902.rs +++ b/tests/ui/lifetimes/tuple-struct-vs-struct-with-fields-borrowck-10902.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10902 + //@ check-pass #![allow(dead_code)] diff --git a/tests/ui/issues/issue-10853.rs b/tests/ui/lint/missing-doc-unsugard-doc-attr-10853.rs index 4c22393d9c0..ec13ae99787 100644 --- a/tests/ui/issues/issue-10853.rs +++ b/tests/ui/lint/missing-doc-unsugard-doc-attr-10853.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10853 + //@ check-pass #![deny(missing_docs)] diff --git a/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.fixed b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.fixed new file mode 100644 index 00000000000..4b0bca3d44a --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.fixed @@ -0,0 +1,12 @@ +//@ run-rustfix + +#![deny(unused_parens)] +#![allow(warnings)] +trait MyTrait {} + +fn foo(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait) + Send + Sync>) {} + +//~v ERROR unnecessary parentheses around type +fn bar(_: Box<dyn FnMut(&mut u32) -> &mut dyn MyTrait>) {} + +fn main() {} diff --git a/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.rs b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.rs new file mode 100644 index 00000000000..4eefd3dc81a --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.rs @@ -0,0 +1,12 @@ +//@ run-rustfix + +#![deny(unused_parens)] +#![allow(warnings)] +trait MyTrait {} + +fn foo(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait) + Send + Sync>) {} + +//~v ERROR unnecessary parentheses around type +fn bar(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait)>) {} + +fn main() {} diff --git a/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.stderr b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.stderr new file mode 100644 index 00000000000..89455e3db73 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-false-positive-issue-143653.stderr @@ -0,0 +1,19 @@ +error: unnecessary parentheses around type + --> $DIR/unused-parens-false-positive-issue-143653.rs:10:43 + | +LL | fn bar(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait)>) {} + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-false-positive-issue-143653.rs:3:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - fn bar(_: Box<dyn FnMut(&mut u32) -> &mut (dyn MyTrait)>) {} +LL + fn bar(_: Box<dyn FnMut(&mut u32) -> &mut dyn MyTrait>) {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/loop-match/suggest-const-item.rs b/tests/ui/loop-match/suggest-const-item.rs new file mode 100644 index 00000000000..f921b430b8c --- /dev/null +++ b/tests/ui/loop-match/suggest-const-item.rs @@ -0,0 +1,174 @@ +#![allow(incomplete_features)] +#![feature(loop_match)] +#![feature(generic_const_items)] +#![crate_type = "lib"] + +const fn const_fn() -> i32 { + 1 +} + +#[unsafe(no_mangle)] +fn suggest_const_block<const N: i32>() -> i32 { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + 0 => { + #[const_continue] + break 'blk const_fn(); + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + 1 => { + #[const_continue] + break 'blk const { const_fn() }; + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + 2 => { + #[const_continue] + break 'blk N; + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + _ => { + #[const_continue] + break 'blk 1 + 1; + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + } + } + } + state +} + +struct S; + +impl S { + const M: usize = 42; + + fn g() { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + 0 => { + #[const_continue] + break 'blk Self::M; + } + _ => panic!(), + } + } + } + } +} + +trait T { + const N: usize; + + fn f() { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + 0 => { + #[const_continue] + break 'blk Self::N; + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + _ => panic!(), + } + } + } + } +} + +impl T for S { + const N: usize = 1; +} + +impl S { + fn h() { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + 0 => { + #[const_continue] + break 'blk Self::N; + } + _ => panic!(), + } + } + } + } +} + +trait T2<U> { + const L: u32; + + fn p() { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + 0 => { + #[const_continue] + break 'blk Self::L; + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + _ => panic!(), + } + } + } + } +} + +const SIZE_OF<T>: usize = size_of::<T>(); + +fn q<T>() { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + 0 => { + #[const_continue] + break 'blk SIZE_OF::<T>; + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + _ => panic!(), + } + } + } +} + +trait Trait<T> { + const X: usize = 9000; + const Y: usize = size_of::<T>(); +} + +impl<T> Trait<T> for () {} + +fn r<T>() { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + 0 => { + #[const_continue] + break 'blk <() as Trait<T>>::X; + } + 1 => { + #[const_continue] + break 'blk <() as Trait<T>>::Y; + //~^ ERROR could not determine the target branch for this `#[const_continue]` + } + _ => panic!(), + } + } + } +} diff --git a/tests/ui/loop-match/suggest-const-item.stderr b/tests/ui/loop-match/suggest-const-item.stderr new file mode 100644 index 00000000000..787474479ad --- /dev/null +++ b/tests/ui/loop-match/suggest-const-item.stderr @@ -0,0 +1,58 @@ +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:19:32 + | +LL | break 'blk const_fn(); + | ^^^^^^^^^^ this value must be a literal or a monomorphic const + | + = help: try extracting the expression into a `const` item + +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:24:32 + | +LL | break 'blk const { const_fn() }; + | ^^^^^^^^^^^^^^^^^^^^ `const` blocks may use generics, and are not evaluated early enough + | + = help: try extracting the expression into a `const` item + +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:29:32 + | +LL | break 'blk N; + | ^ constant parameters may use generics, and are not evaluated early enough + | + = help: try extracting the expression into a `const` item + +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:34:32 + | +LL | break 'blk 1 + 1; + | ^^^^^ this value must be a literal or a monomorphic const + | + = help: try extracting the expression into a `const` item + +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:76:36 + | +LL | break 'blk Self::N; + | ^^^^^^^ this value is too generic + +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:119:36 + | +LL | break 'blk Self::L; + | ^^^^^^^ this value is too generic + +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:139:32 + | +LL | break 'blk SIZE_OF::<T>; + | ^^^^^^^^^^^^ this value is too generic + +error: could not determine the target branch for this `#[const_continue]` + --> $DIR/suggest-const-item.rs:167:32 + | +LL | break 'blk <() as Trait<T>>::Y; + | ^^^^^^^^^^^^^^^^^^^ this value is too generic + +error: aborting due to 8 previous errors + diff --git a/tests/ui/lto/all-crates.rs b/tests/ui/lto/all-crates.rs index ceabf9f05df..fa17684dcff 100644 --- a/tests/ui/lto/all-crates.rs +++ b/tests/ui/lto/all-crates.rs @@ -2,6 +2,7 @@ //@ compile-flags: -Clto=thin //@ no-prefer-dynamic +//@ ignore-backends: gcc fn main() { println!("hello!"); diff --git a/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs b/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs index a38d0e2b2e3..8579fd599f7 100644 --- a/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs +++ b/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ compile-flags: -C lto=thin //@ aux-build:lto-rustc-loads-linker-plugin.rs //@ run-pass diff --git a/tests/ui/lto/thin-lto-inlines2.rs b/tests/ui/lto/thin-lto-inlines2.rs index 735557ab491..4c7b9278b08 100644 --- a/tests/ui/lto/thin-lto-inlines2.rs +++ b/tests/ui/lto/thin-lto-inlines2.rs @@ -4,6 +4,7 @@ //@ aux-build:thin-lto-inlines-aux.rs //@ no-prefer-dynamic //@ ignore-emscripten can't inspect instructions on emscripten +//@ ignore-backends: gcc // We want to assert here that ThinLTO will inline across codegen units. There's // not really a great way to do that in general so we sort of hack around it by diff --git a/tests/ui/issues/issue-34418.rs b/tests/ui/macros/macro-invocation-with-curly-braces-34418.rs index 0dcefb01935..46dbdd35ef6 100644 --- a/tests/ui/issues/issue-34418.rs +++ b/tests/ui/macros/macro-invocation-with-curly-braces-34418.rs @@ -17,3 +17,5 @@ fn g() { } fn main() {} + +// https://github.com/rust-lang/rust/issues/34418 diff --git a/tests/ui/macros/trace-macro.rs b/tests/ui/macros/trace-macro.rs index ecc6aabe8ca..a85f8f42e7a 100644 --- a/tests/ui/macros/trace-macro.rs +++ b/tests/ui/macros/trace-macro.rs @@ -3,4 +3,7 @@ fn main() { println!("Hello, World!"); + //~^ NOTE trace_macro + //~| NOTE expanding `println! + //~| NOTE to `{ } diff --git a/tests/ui/issues/issue-106755.rs b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs index d7e7122ebda..891b8c1f74d 100644 --- a/tests/ui/issues/issue-106755.rs +++ b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs @@ -20,3 +20,5 @@ impl !Send for TestType<i32> {} //~^ ERROR `!Send` impls cannot be specialized fn main() {} + +// https://github.com/rust-lang/rust/issues/106755 diff --git a/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr new file mode 100644 index 00000000000..100b3bf1ae3 --- /dev/null +++ b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr @@ -0,0 +1,47 @@ +error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`: + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:13:1 + | +LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {} + | ------------------------------------------------------ positive implementation here +LL | +LL | impl<T: MyTrait> !Send for TestType<T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here + +error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>` + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:17:1 + | +LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {} + | ------------------------------------------------------ first implementation here +... +LL | unsafe impl<T: 'static> Send for TestType<T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` + +error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:13:9 + | +LL | impl<T: MyTrait> !Send for TestType<T> {} + | ^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:9:1 + | +LL | struct TestType<T>(::std::marker::PhantomData<T>); + | ^^^^^^^^^^^^^^^^^^ + +error[E0366]: `!Send` impls cannot be specialized + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:19:1 + | +LL | impl !Send for TestType<i32> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `i32` is not a generic parameter +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:9:1 + | +LL | struct TestType<T>(::std::marker::PhantomData<T>); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0119, E0366, E0367, E0751. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/issues/issue-46964.rs b/tests/ui/match/innocent-looking-match-crash-46964.rs index 6a29d91df73..c3efe874703 100644 --- a/tests/ui/issues/issue-46964.rs +++ b/tests/ui/match/innocent-looking-match-crash-46964.rs @@ -17,3 +17,5 @@ pub fn crash() -> bool { } fn main() {} + +// https://github.com/rust-lang/rust/issues/46964 diff --git a/tests/ui/issues/issue-53843.rs b/tests/ui/methods/inherent-method-resolution-on-deref-type-53843.rs index d4b0b1e332b..0b2ab9afc39 100644 --- a/tests/ui/issues/issue-53843.rs +++ b/tests/ui/methods/inherent-method-resolution-on-deref-type-53843.rs @@ -24,3 +24,5 @@ fn main() { let pin = Pin(&mut unit); pin.poll(); } + +// https://github.com/rust-lang/rust/issues/53843 diff --git a/tests/ui/mir/mir_drop_order.rs b/tests/ui/mir/mir_drop_order.rs index 21d1054c422..a7a1a26a956 100644 --- a/tests/ui/mir/mir_drop_order.rs +++ b/tests/ui/mir/mir_drop_order.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc use std::cell::RefCell; use std::panic; diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs index 8a54f21b57f..1579e298ee7 100644 --- a/tests/ui/mir/mir_let_chains_drop_order.rs +++ b/tests/ui/mir/mir_let_chains_drop_order.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc //@ edition: 2024 // See `mir_drop_order.rs` for more information diff --git a/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs index e98d57d1154..3196513454b 100644 --- a/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs +++ b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc //@ revisions: edition2021 edition2024 //@ [edition2021] edition: 2021 //@ [edition2024] edition: 2024 diff --git a/tests/ui/mir/static-by-value-dyn.rs b/tests/ui/mir/static-by-value-dyn.rs new file mode 100644 index 00000000000..f1154ef0860 --- /dev/null +++ b/tests/ui/mir/static-by-value-dyn.rs @@ -0,0 +1,14 @@ +//! Regression test for #121176 +//! KnownPanicsLint used to assert ABI compatibility in the interpreter, +//! which ICEs with unsized statics. +//@ needs-rustc-debug-assertions + +use std::fmt::Debug; + +static STATIC_1: dyn Debug + Sync = *(); +//~^ ERROR the size for values of type `(dyn Debug + Sync + 'static)` cannot be known +//~| ERROR type `()` cannot be dereferenced + +fn main() { + println!("{:?}", &STATIC_1); +} diff --git a/tests/ui/mir/static-by-value-dyn.stderr b/tests/ui/mir/static-by-value-dyn.stderr new file mode 100644 index 00000000000..25ed81326f4 --- /dev/null +++ b/tests/ui/mir/static-by-value-dyn.stderr @@ -0,0 +1,19 @@ +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time + --> $DIR/static-by-value-dyn.rs:8:1 + | +LL | static STATIC_1: dyn Debug + Sync = *(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` + = note: statics and constants must have a statically known size + +error[E0614]: type `()` cannot be dereferenced + --> $DIR/static-by-value-dyn.rs:8:37 + | +LL | static STATIC_1: dyn Debug + Sync = *(); + | ^^^ can't be dereferenced + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0614. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/mir/static-by-value-slice.rs b/tests/ui/mir/static-by-value-slice.rs new file mode 100644 index 00000000000..af98be6a74d --- /dev/null +++ b/tests/ui/mir/static-by-value-slice.rs @@ -0,0 +1,10 @@ +//! Regression test for #140332 +//! KnownPanicsLint used to assert ABI compatibility in the interpreter, +//! which ICEs with unsized statics. + +static mut S: [i8] = ["Some thing"; 1]; +//~^ ERROR the size for values of type `[i8]` cannot be known + +fn main() { + assert_eq!(S, [0; 1]); +} diff --git a/tests/ui/mir/static-by-value-slice.stderr b/tests/ui/mir/static-by-value-slice.stderr new file mode 100644 index 00000000000..2d0592943d0 --- /dev/null +++ b/tests/ui/mir/static-by-value-slice.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `[i8]` cannot be known at compilation time + --> $DIR/static-by-value-slice.rs:5:1 + | +LL | static mut S: [i8] = ["Some thing"; 1]; + | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i8]` + = note: statics and constants must have a statically known size + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mir/static-by-value-str.rs b/tests/ui/mir/static-by-value-str.rs new file mode 100644 index 00000000000..88b72f90819 --- /dev/null +++ b/tests/ui/mir/static-by-value-str.rs @@ -0,0 +1,15 @@ +//! Regression test for #139872 +//! KnownPanicsLint used to assert ABI compatibility in the interpreter, +//! which ICEs with unsized statics. + +enum E { + V16(u16), + V32(u32), +} + +static C: (E, u16, str) = (E::V16(0xDEAD), 0x600D, 0xBAD); +//~^ ERROR the size for values of type `str` cannot be known + +pub fn main() { + let (_, n, _) = C; +} diff --git a/tests/ui/mir/static-by-value-str.stderr b/tests/ui/mir/static-by-value-str.stderr new file mode 100644 index 00000000000..6e046e00551 --- /dev/null +++ b/tests/ui/mir/static-by-value-str.stderr @@ -0,0 +1,13 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/static-by-value-str.rs:10:1 + | +LL | static C: (E, u16, str) = (E::V16(0xDEAD), 0x600D, 0xBAD); + | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `(E, u16, str)`, the trait `Sized` is not implemented for `str` + = note: required because it appears within the type `(E, u16, str)` + = note: statics and constants must have a statically known size + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mir/unsized-extern-static.rs b/tests/ui/mir/unsized-extern-static.rs new file mode 100644 index 00000000000..386842556ba --- /dev/null +++ b/tests/ui/mir/unsized-extern-static.rs @@ -0,0 +1,13 @@ +//! Regression test for #129109 +//! MIR building used to produce erroneous constants when referring to statics of unsized type. +//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir + +extern "C" { + pub static mut symbol: [i8]; + //~^ ERROR the size for values of type `[i8]` +} + +fn main() { + println!("C", unsafe { &symbol }); + //~^ ERROR argument never used +} diff --git a/tests/ui/mir/unsized-extern-static.stderr b/tests/ui/mir/unsized-extern-static.stderr new file mode 100644 index 00000000000..93aed3549d7 --- /dev/null +++ b/tests/ui/mir/unsized-extern-static.stderr @@ -0,0 +1,20 @@ +error: argument never used + --> $DIR/unsized-extern-static.rs:11:19 + | +LL | println!("C", unsafe { &symbol }); + | --- ^^^^^^^^^^^^^^^^^^ argument never used + | | + | formatting specifier missing + +error[E0277]: the size for values of type `[i8]` cannot be known at compilation time + --> $DIR/unsized-extern-static.rs:6:5 + | +LL | pub static mut symbol: [i8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i8]` + = note: statics and constants must have a statically known size + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr index c626796e01d..6272455cc57 100644 --- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr @@ -8,6 +8,14 @@ LL | let mut copy: Vec<U> = map.clone().into_values().collect(); | note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +note: if `Hash128_1` implemented `Clone`, you could clone the value + --> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:8:1 + | +LL | pub struct Hash128_1; + | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let mut copy: Vec<U> = map.clone().into_values().collect(); + | ----------- you could clone this value help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied | LL - let mut copy: Vec<U> = map.clone().into_values().collect(); diff --git a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr index 63f230be7d4..3363c4ea28b 100644 --- a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr +++ b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr @@ -27,6 +27,15 @@ LL | drop(d); | - value moved here LL | d.x = 10; | ^^^^^^^^ value assigned here after move + | +note: if `D` implemented `Clone`, you could clone the value + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:11:1 + | +LL | struct D { + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(d); + | - you could clone this value error[E0381]: partially assigned binding `d` isn't fully initialized --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5 @@ -57,6 +66,15 @@ LL | drop(d); | - value moved here LL | d.s.y = 20; | ^^^^^^^^^^ value partially assigned here after move + | +note: if `D` implemented `Clone`, you could clone the value + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:11:1 + | +LL | struct D { + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(d); + | - you could clone this value error: aborting due to 6 previous errors diff --git a/tests/ui/numbers-arithmetic/u128-as-f32.rs b/tests/ui/numbers-arithmetic/u128-as-f32.rs index 88579f507eb..57c82d5a24f 100644 --- a/tests/ui/numbers-arithmetic/u128-as-f32.rs +++ b/tests/ui/numbers-arithmetic/u128-as-f32.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![feature(test)] #![deny(overflowing_literals)] diff --git a/tests/ui/offset-of/offset-of-tuple-field.rs b/tests/ui/offset-of/offset-of-tuple-field.rs new file mode 100644 index 00000000000..02d41f91a25 --- /dev/null +++ b/tests/ui/offset-of/offset-of-tuple-field.rs @@ -0,0 +1,22 @@ +#![feature(builtin_syntax)] + +use std::mem::offset_of; + +fn main() { + offset_of!((u8, u8), _0); //~ ERROR no field `_0` + offset_of!((u8, u8), 01); //~ ERROR no field `01` + offset_of!((u8, u8), 1e2); //~ ERROR no field `1e2` + offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_` + //~| ERROR suffixes on a tuple index + + builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2` + builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0` + builtin # offset_of((u8, u8), 01); //~ ERROR no field `01` + builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_` + //~| ERROR suffixes on a tuple index + + offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2` + offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); //~ ERROR no field `1e2` + offset_of!(((u8, u16), (u32, u16, u8)), 1.2); + offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0` +} diff --git a/tests/ui/offset-of/offset-of-tuple-field.stderr b/tests/ui/offset-of/offset-of-tuple-field.stderr new file mode 100644 index 00000000000..4da0d851650 --- /dev/null +++ b/tests/ui/offset-of/offset-of-tuple-field.stderr @@ -0,0 +1,81 @@ +error: suffixes on a tuple index are invalid + --> $DIR/offset-of-tuple-field.rs:15:35 + | +LL | builtin # offset_of((u8, u8), 1_u8); + | ^^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/offset-of-tuple-field.rs:9:26 + | +LL | offset_of!((u8, u8), 1_u8); + | ^^^^ invalid suffix `u8` + +error[E0609]: no field `_0` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:6:26 + | +LL | offset_of!((u8, u8), _0); + | ^^ + +error[E0609]: no field `01` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:7:26 + | +LL | offset_of!((u8, u8), 01); + | ^^ + +error[E0609]: no field `1e2` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:8:26 + | +LL | offset_of!((u8, u8), 1e2); + | ^^^ + +error[E0609]: no field `1_` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:9:26 + | +LL | offset_of!((u8, u8), 1_u8); + | ^^^^ + +error[E0609]: no field `1e2` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:12:35 + | +LL | builtin # offset_of((u8, u8), 1e2); + | ^^^ + +error[E0609]: no field `_0` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:13:35 + | +LL | builtin # offset_of((u8, u8), _0); + | ^^ + +error[E0609]: no field `01` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:14:35 + | +LL | builtin # offset_of((u8, u8), 01); + | ^^ + +error[E0609]: no field `1_` on type `(u8, u8)` + --> $DIR/offset-of-tuple-field.rs:15:35 + | +LL | builtin # offset_of((u8, u8), 1_u8); + | ^^^^ + +error[E0609]: no field `2` on type `(u8, u16)` + --> $DIR/offset-of-tuple-field.rs:18:47 + | +LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); + | ^ + +error[E0609]: no field `1e2` on type `(u8, u16)` + --> $DIR/offset-of-tuple-field.rs:19:47 + | +LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); + | ^^^ + +error[E0609]: no field `0` on type `u8` + --> $DIR/offset-of-tuple-field.rs:21:49 + | +LL | offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); + | ^ + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs index e8447249441..ddbaee97b1b 100644 --- a/tests/ui/offset-of/offset-of-tuple.rs +++ b/tests/ui/offset-of/offset-of-tuple.rs @@ -3,20 +3,10 @@ use std::mem::offset_of; fn main() { - offset_of!((u8, u8), _0); //~ ERROR no field `_0` - offset_of!((u8, u8), 01); //~ ERROR no field `01` - offset_of!((u8, u8), 1e2); //~ ERROR no field `1e2` - offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_` - //~| ERROR suffixes on a tuple index offset_of!((u8, u8), +1); //~ ERROR no rules expected offset_of!((u8, u8), -1); //~ ERROR offset_of expects dot-separated field and variant names offset_of!((u8, u8), 1.); //~ ERROR offset_of expects dot-separated field and variant names offset_of!((u8, u8), 1 .); //~ ERROR unexpected token: `)` - builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2` - builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0` - builtin # offset_of((u8, u8), 01); //~ ERROR no field `01` - builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_` - //~| ERROR suffixes on a tuple index // We need to put these into curly braces, otherwise only one of the // errors will be emitted and the others suppressed. { builtin # offset_of((u8, u8), +1) }; //~ ERROR leading `+` is not supported @@ -27,11 +17,6 @@ fn main() { type ComplexTup = (((u8, u8), u8), u8); fn nested() { - offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2` - offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); //~ ERROR no field `1e2` - offset_of!(((u8, u16), (u32, u16, u8)), 1.2); - offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0` - // All combinations of spaces (this sends different tokens to the parser) offset_of!(ComplexTup, 0.0.1.); //~ ERROR unexpected token: `)` offset_of!(ComplexTup, 0 .0.1.); //~ ERROR unexpected token: `)` diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index 38ce49c9179..33dea9918ca 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -1,11 +1,5 @@ -error: suffixes on a tuple index are invalid - --> $DIR/offset-of-tuple.rs:18:35 - | -LL | builtin # offset_of((u8, u8), 1_u8); - | ^^^^ invalid suffix `u8` - error: leading `+` is not supported - --> $DIR/offset-of-tuple.rs:22:37 + --> $DIR/offset-of-tuple.rs:12:37 | LL | { builtin # offset_of((u8, u8), +1) }; | ^ unexpected `+` @@ -17,67 +11,61 @@ LL + { builtin # offset_of((u8, u8), 1) }; | error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-tuple.rs:23:38 + --> $DIR/offset-of-tuple.rs:13:38 | LL | { builtin # offset_of((u8, u8), 1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:24:40 + --> $DIR/offset-of-tuple.rs:14:40 | LL | { builtin # offset_of((u8, u8), 1 .) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:47:45 + --> $DIR/offset-of-tuple.rs:32:45 | LL | { builtin # offset_of(ComplexTup, 0.0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:48:46 + --> $DIR/offset-of-tuple.rs:33:46 | LL | { builtin # offset_of(ComplexTup, 0 .0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:49:47 + --> $DIR/offset-of-tuple.rs:34:47 | LL | { builtin # offset_of(ComplexTup, 0 . 0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:50:46 + --> $DIR/offset-of-tuple.rs:35:46 | LL | { builtin # offset_of(ComplexTup, 0. 0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:51:46 + --> $DIR/offset-of-tuple.rs:36:46 | LL | { builtin # offset_of(ComplexTup, 0.0 .1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:52:47 + --> $DIR/offset-of-tuple.rs:37:47 | LL | { builtin # offset_of(ComplexTup, 0.0 . 1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:53:46 + --> $DIR/offset-of-tuple.rs:38:46 | LL | { builtin # offset_of(ComplexTup, 0.0. 1.) }; | ^ -error: suffixes on a tuple index are invalid - --> $DIR/offset-of-tuple.rs:9:26 - | -LL | offset_of!((u8, u8), 1_u8); - | ^^^^ invalid suffix `u8` - error: no rules expected `+` - --> $DIR/offset-of-tuple.rs:11:26 + --> $DIR/offset-of-tuple.rs:6:26 | LL | offset_of!((u8, u8), +1); | ^ no rules expected this token in macro call @@ -86,131 +74,64 @@ note: while trying to match meta-variable `$fields:expr` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-tuple.rs:12:26 + --> $DIR/offset-of-tuple.rs:7:26 | LL | offset_of!((u8, u8), -1); | ^^ error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-tuple.rs:13:27 + --> $DIR/offset-of-tuple.rs:8:27 | LL | offset_of!((u8, u8), 1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:14:29 + --> $DIR/offset-of-tuple.rs:9:29 | LL | offset_of!((u8, u8), 1 .); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:36:34 + --> $DIR/offset-of-tuple.rs:21:34 | LL | offset_of!(ComplexTup, 0.0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:37:35 + --> $DIR/offset-of-tuple.rs:22:35 | LL | offset_of!(ComplexTup, 0 .0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:38:36 + --> $DIR/offset-of-tuple.rs:23:36 | LL | offset_of!(ComplexTup, 0 . 0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:39:35 + --> $DIR/offset-of-tuple.rs:24:35 | LL | offset_of!(ComplexTup, 0. 0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:40:35 + --> $DIR/offset-of-tuple.rs:25:35 | LL | offset_of!(ComplexTup, 0.0 .1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:41:36 + --> $DIR/offset-of-tuple.rs:26:36 | LL | offset_of!(ComplexTup, 0.0 . 1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:42:35 + --> $DIR/offset-of-tuple.rs:27:35 | LL | offset_of!(ComplexTup, 0.0. 1.); | ^ -error[E0609]: no field `_0` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:6:26 - | -LL | offset_of!((u8, u8), _0); - | ^^ - -error[E0609]: no field `01` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:7:26 - | -LL | offset_of!((u8, u8), 01); - | ^^ - -error[E0609]: no field `1e2` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:8:26 - | -LL | offset_of!((u8, u8), 1e2); - | ^^^ - -error[E0609]: no field `1_` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:9:26 - | -LL | offset_of!((u8, u8), 1_u8); - | ^^^^ - -error[E0609]: no field `1e2` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:15:35 - | -LL | builtin # offset_of((u8, u8), 1e2); - | ^^^ - -error[E0609]: no field `_0` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:16:35 - | -LL | builtin # offset_of((u8, u8), _0); - | ^^ - -error[E0609]: no field `01` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:17:35 - | -LL | builtin # offset_of((u8, u8), 01); - | ^^ - -error[E0609]: no field `1_` on type `(u8, u8)` - --> $DIR/offset-of-tuple.rs:18:35 - | -LL | builtin # offset_of((u8, u8), 1_u8); - | ^^^^ - -error[E0609]: no field `2` on type `(u8, u16)` - --> $DIR/offset-of-tuple.rs:30:47 - | -LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); - | ^ - -error[E0609]: no field `1e2` on type `(u8, u16)` - --> $DIR/offset-of-tuple.rs:31:47 - | -LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); - | ^^^ - -error[E0609]: no field `0` on type `u8` - --> $DIR/offset-of-tuple.rs:33:49 - | -LL | offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); - | ^ - -error: aborting due to 34 previous errors +error: aborting due to 21 previous errors -For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs index 0566d2319df..bef2d8bcff0 100644 --- a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs +++ b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs @@ -3,6 +3,7 @@ //@ aux-build:exit-success-if-unwind.rs //@ no-prefer-dynamic //@ needs-subprocess +//@ ignore-backends: gcc extern crate exit_success_if_unwind; diff --git a/tests/ui/panic-runtime/abort.rs b/tests/ui/panic-runtime/abort.rs index 8cdfd018a92..2a52228801f 100644 --- a/tests/ui/panic-runtime/abort.rs +++ b/tests/ui/panic-runtime/abort.rs @@ -2,6 +2,7 @@ //@ compile-flags:-C panic=abort //@ no-prefer-dynamic //@ needs-subprocess +//@ ignore-backends: gcc use std::env; use std::process::Command; diff --git a/tests/ui/panic-runtime/link-to-abort.rs b/tests/ui/panic-runtime/link-to-abort.rs index a4013f2a6cf..98718ab8342 100644 --- a/tests/ui/panic-runtime/link-to-abort.rs +++ b/tests/ui/panic-runtime/link-to-abort.rs @@ -2,6 +2,7 @@ //@ compile-flags:-C panic=abort //@ no-prefer-dynamic +//@ ignore-backends: gcc #![feature(panic_abort)] diff --git a/tests/ui/panic-runtime/lto-abort.rs b/tests/ui/panic-runtime/lto-abort.rs index cf15ae6435b..cf36cd8c810 100644 --- a/tests/ui/panic-runtime/lto-abort.rs +++ b/tests/ui/panic-runtime/lto-abort.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ run-pass //@ compile-flags:-C lto -C panic=abort //@ no-prefer-dynamic diff --git a/tests/ui/issues/issue-10638.rs b/tests/ui/parser/doc-comment-parsing.rs index c6c6939bda5..00f6b0e09a8 100644 --- a/tests/ui/issues/issue-10638.rs +++ b/tests/ui/parser/doc-comment-parsing.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10638 + //@ run-pass pub fn main() { diff --git a/tests/ui/parser/unclosed-delimiter-in-dep.rs b/tests/ui/parser/unclosed-delimiter-in-dep.rs index 40f517f317e..4f0423a704f 100644 --- a/tests/ui/parser/unclosed-delimiter-in-dep.rs +++ b/tests/ui/parser/unclosed-delimiter-in-dep.rs @@ -1,3 +1,5 @@ +//@ ignore-backends: gcc + mod unclosed_delim_mod; fn main() { diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr index f19fed08917..deb14d141a9 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -146,6 +146,15 @@ LL | m!((ref mut borrow, mov) = tup0); ... LL | drop(&tup0); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!((ref mut borrow, mov) = tup0); + | ---- you could clone this value error[E0382]: borrow of moved value: `tup1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10 @@ -161,6 +170,15 @@ LL | m!((mov, _, ref mut borrow) = tup1); ... LL | drop(&tup1); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!((mov, _, ref mut borrow) = tup1); + | ---- you could clone this value error[E0382]: borrow of moved value: `tup2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 @@ -176,6 +194,15 @@ LL | m!((ref borrow, mov) = tup2); ... LL | drop(&tup2); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!((ref borrow, mov) = tup2); + | ---- you could clone this value error[E0382]: borrow of moved value: `tup3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 @@ -191,6 +218,15 @@ LL | m!((mov, _, ref borrow) = tup3); ... LL | drop(&tup3); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!((mov, _, ref borrow) = tup3); + | ---- you could clone this value error[E0382]: borrow of moved value: `tup4` --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21 @@ -206,6 +242,15 @@ LL | m!((ref borrow, mov) = tup4); ... LL | m!((ref x, _) = &tup4); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!((ref borrow, mov) = tup4); + | ---- you could clone this value error[E0382]: borrow of moved value: `arr0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 @@ -221,6 +266,15 @@ LL | m!([mov @ .., ref borrow] = arr0); ... LL | drop(&arr0); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!([mov @ .., ref borrow] = arr0); + | ---- you could clone this value error[E0382]: borrow of moved value: `arr1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35 @@ -236,6 +290,15 @@ LL | m!([_, ref mut borrow @ .., _, mov] = arr1); ... LL | m!([_, mov1, mov2, mov3, _] = &arr1); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!([_, ref mut borrow @ .., _, mov] = arr1); + | ---- you could clone this value error[E0382]: borrow of moved value: `arr2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 @@ -251,6 +314,15 @@ LL | m!([mov @ .., ref borrow] = arr2); ... LL | drop(&arr2); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!([mov @ .., ref borrow] = arr2); + | ---- you could clone this value error[E0382]: borrow of moved value: `arr3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 @@ -265,6 +337,15 @@ LL | m!([_, ref borrow @ .., _, mov] = arr3); ... LL | m!([_, mov1, mov2, mov3, _] = &arr3); | ^^^^^ value borrowed here after move + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-ref-patterns-closure-captures-inside.rs:2:5 + | +LL | struct S; // Not `Copy`. + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | m!([_, ref borrow @ .., _, mov] = arr3); + | ---- you could clone this value error[E0382]: borrow of moved value: `tup0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10 diff --git a/tests/ui/issues/issue-10683.rs b/tests/ui/pattern/premature-match-scrutinee-temporary-drop-10683.rs index 5657ec1864b..a4dfa56117c 100644 --- a/tests/ui/issues/issue-10683.rs +++ b/tests/ui/pattern/premature-match-scrutinee-temporary-drop-10683.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10683 + //@ run-pass static NAME: &'static str = "hello world"; diff --git a/tests/ui/issues/issue-54062.rs b/tests/ui/privacy/private-field-access-in-mutex-54062.rs index 093d6601d4e..f145f9c3e52 100644 --- a/tests/ui/issues/issue-54062.rs +++ b/tests/ui/privacy/private-field-access-in-mutex-54062.rs @@ -10,3 +10,5 @@ fn testing(test: Test) { let _ = test.comps.inner.try_lock(); //~^ ERROR: field `inner` of struct `Mutex` is private } + +// https://github.com/rust-lang/rust/issues/54062 diff --git a/tests/ui/issues/issue-54062.stderr b/tests/ui/privacy/private-field-access-in-mutex-54062.stderr index 75eef543f27..14244107597 100644 --- a/tests/ui/issues/issue-54062.stderr +++ b/tests/ui/privacy/private-field-access-in-mutex-54062.stderr @@ -1,5 +1,5 @@ error[E0616]: field `inner` of struct `Mutex` is private - --> $DIR/issue-54062.rs:10:24 + --> $DIR/private-field-access-in-mutex-54062.rs:10:24 | LL | let _ = test.comps.inner.try_lock(); | ^^^^^ private field diff --git a/tests/ui/issues/issue-10545.rs b/tests/ui/privacy/struct-field-and-impl-expose-10545.rs index acd07149619..8a8c8240c2d 100644 --- a/tests/ui/issues/issue-10545.rs +++ b/tests/ui/privacy/struct-field-and-impl-expose-10545.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10545 + mod a { struct S; impl S { } diff --git a/tests/ui/issues/issue-10545.stderr b/tests/ui/privacy/struct-field-and-impl-expose-10545.stderr index 9aa04217174..ddf87d1d23a 100644 --- a/tests/ui/issues/issue-10545.stderr +++ b/tests/ui/privacy/struct-field-and-impl-expose-10545.stderr @@ -1,11 +1,11 @@ error[E0603]: struct `S` is private - --> $DIR/issue-10545.rs:6:14 + --> $DIR/struct-field-and-impl-expose-10545.rs:8:14 | LL | fn foo(_: a::S) { | ^ private struct | note: the struct `S` is defined here - --> $DIR/issue-10545.rs:2:5 + --> $DIR/struct-field-and-impl-expose-10545.rs:4:5 | LL | struct S; | ^^^^^^^^^ diff --git a/tests/ui/proc-macro/attribute.rs b/tests/ui/proc-macro/attribute.rs index 30ed8ff8247..988cdcd0403 100644 --- a/tests/ui/proc-macro/attribute.rs +++ b/tests/ui/proc-macro/attribute.rs @@ -6,68 +6,85 @@ extern crate proc_macro; use proc_macro::*; -#[proc_macro_derive] //~ ERROR malformed `proc_macro_derive` attribute +#[proc_macro_derive] +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected this to be a list pub fn foo1(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive = ""] //~ ERROR malformed `proc_macro_derive` attribute +#[proc_macro_derive = ""] +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected this to be a list pub fn foo2(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d3, a, b)] -//~^ ERROR attribute must have either one or two arguments +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE the only valid argument here is `attributes` pub fn foo3(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d4, attributes(a), b)] -//~^ ERROR attribute must have either one or two arguments +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE didn't expect any arguments here pub fn foo4(input: TokenStream) -> TokenStream { input } #[proc_macro_derive("a")] -//~^ ERROR: not a meta item +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE didn't expect a literal here pub fn foo5(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d6 = "")] -//~^ ERROR: must only be one word +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE didn't expect any arguments here pub fn foo6(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(m::d7)] -//~^ ERROR: must only be one word +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected a valid identifier here pub fn foo7(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d8(a))] -//~^ ERROR: must only be one word +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE didn't expect any arguments here pub fn foo8(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(self)] -//~^ ERROR: `self` cannot be a name of derive macro +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected a valid identifier here pub fn foo9(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(PartialEq)] // OK pub fn foo10(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d11, a)] -//~^ ERROR: second argument must be `attributes` -//~| ERROR: attribute must be of form: `attributes(foo, bar)` +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE the only valid argument here is `attributes` pub fn foo11(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d12, attributes)] -//~^ ERROR: attribute must be of form: `attributes(foo, bar)` +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected this to be a list pub fn foo12(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d13, attributes("a"))] -//~^ ERROR: attribute must be a meta item, not a literal +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected a valid identifier here pub fn foo13(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d14, attributes(a = ""))] -//~^ ERROR: attribute must only be a single word +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE didn't expect any arguments here pub fn foo14(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d15, attributes(m::a))] -//~^ ERROR: attribute must only be a single word +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected a valid identifier here pub fn foo15(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d16, attributes(a(b)))] -//~^ ERROR: attribute must only be a single word +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE didn't expect any arguments here pub fn foo16(input: TokenStream) -> TokenStream { input } #[proc_macro_derive(d17, attributes(self))] -//~^ ERROR: `self` cannot be a name of derive helper attribute +//~^ ERROR malformed `proc_macro_derive` attribute +//~| NOTE expected a valid identifier here pub fn foo17(input: TokenStream) -> TokenStream { input } diff --git a/tests/ui/proc-macro/attribute.stderr b/tests/ui/proc-macro/attribute.stderr index 3269aaf7f91..db59a1fdfb3 100644 --- a/tests/ui/proc-macro/attribute.stderr +++ b/tests/ui/proc-macro/attribute.stderr @@ -1,104 +1,148 @@ -error: malformed `proc_macro_derive` attribute input +error[E0539]: malformed `proc_macro_derive` attribute input --> $DIR/attribute.rs:9:1 | LL | #[proc_macro_derive] - | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` + | ^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:12:1 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:14:1 | LL | #[proc_macro_derive = ""] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must have either one or two arguments - --> $DIR/attribute.rs:15:1 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:19:1 | LL | #[proc_macro_derive(d3, a, b)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^ + | | | + | | the only valid argument here is `attributes` + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must have either one or two arguments - --> $DIR/attribute.rs:19:1 +error[E0565]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:24:1 | LL | #[proc_macro_derive(d4, attributes(a), b)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: not a meta item - --> $DIR/attribute.rs:23:21 +error[E0565]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:29:1 | LL | #[proc_macro_derive("a")] - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^---^^ + | | | + | | didn't expect a literal here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: must only be one word - --> $DIR/attribute.rs:27:21 +error[E0565]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:34:1 | LL | #[proc_macro_derive(d6 = "")] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^----^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: must only be one word - --> $DIR/attribute.rs:31:21 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:39:1 | LL | #[proc_macro_derive(m::d7)] - | ^^^^^ + | ^^^^^^^^^^^^^^^^^^^^-----^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: must only be one word - --> $DIR/attribute.rs:35:21 +error[E0565]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:44:1 | LL | #[proc_macro_derive(d8(a))] - | ^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^---^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: `self` cannot be a name of derive macro - --> $DIR/attribute.rs:39:21 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:49:1 | LL | #[proc_macro_derive(self)] - | ^^^^ - -error: second argument must be `attributes` - --> $DIR/attribute.rs:46:26 - | -LL | #[proc_macro_derive(d11, a)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^----^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must be of form: `attributes(foo, bar)` - --> $DIR/attribute.rs:46:26 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:57:1 | LL | #[proc_macro_derive(d11, a)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | | + | | the only valid argument here is `attributes` + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must be of form: `attributes(foo, bar)` - --> $DIR/attribute.rs:51:26 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:62:1 | LL | #[proc_macro_derive(d12, attributes)] - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^----------^^ + | | | + | | expected this to be a list + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must be a meta item, not a literal - --> $DIR/attribute.rs:55:37 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:67:1 | LL | #[proc_macro_derive(d13, attributes("a"))] - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must only be a single word - --> $DIR/attribute.rs:59:37 +error[E0565]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:72:1 | LL | #[proc_macro_derive(d14, attributes(a = ""))] - | ^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must only be a single word - --> $DIR/attribute.rs:63:37 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:77:1 | LL | #[proc_macro_derive(d15, attributes(m::a))] - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must only be a single word - --> $DIR/attribute.rs:67:37 +error[E0565]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:82:1 | LL | #[proc_macro_derive(d16, attributes(a(b)))] - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: `self` cannot be a name of derive helper attribute - --> $DIR/attribute.rs:71:37 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:87:1 | LL | #[proc_macro_derive(d17, attributes(self))] - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors +Some errors have detailed explanations: E0539, E0565. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/proc-macro/invalid-attributes.rs b/tests/ui/proc-macro/invalid-attributes.rs index a70c73e9b8f..703defad69b 100644 --- a/tests/ui/proc-macro/invalid-attributes.rs +++ b/tests/ui/proc-macro/invalid-attributes.rs @@ -7,20 +7,32 @@ extern crate proc_macro; use proc_macro::TokenStream; -#[proc_macro = "test"] //~ ERROR malformed `proc_macro` attribute +#[proc_macro = "test"] +//~^ ERROR malformed `proc_macro` attribute +//~| NOTE didn't expect any arguments here pub fn a(a: TokenStream) -> TokenStream { a } -#[proc_macro()] //~ ERROR malformed `proc_macro` attribute +#[proc_macro()] +//~^ ERROR malformed `proc_macro` attribute +//~| NOTE didn't expect any arguments here pub fn c(a: TokenStream) -> TokenStream { a } -#[proc_macro(x)] //~ ERROR malformed `proc_macro` attribute +#[proc_macro(x)] +//~^ ERROR malformed `proc_macro` attribute +//~| NOTE didn't expect any arguments here pub fn d(a: TokenStream) -> TokenStream { a } -#[proc_macro_attribute = "test"] //~ ERROR malformed `proc_macro_attribute` attribute +#[proc_macro_attribute = "test"] +//~^ ERROR malformed `proc_macro_attribute` attribute +//~| NOTE didn't expect any arguments here pub fn e(_: TokenStream, a: TokenStream) -> TokenStream { a } -#[proc_macro_attribute()] //~ ERROR malformed `proc_macro_attribute` attribute +#[proc_macro_attribute()] +//~^ ERROR malformed `proc_macro_attribute` attribute +//~| NOTE didn't expect any arguments here pub fn g(_: TokenStream, a: TokenStream) -> TokenStream { a } -#[proc_macro_attribute(x)] //~ ERROR malformed `proc_macro_attribute` attribute +#[proc_macro_attribute(x)] +//~^ ERROR malformed `proc_macro_attribute` attribute +//~| NOTE didn't expect any arguments here pub fn h(_: TokenStream, a: TokenStream) -> TokenStream { a } diff --git a/tests/ui/proc-macro/invalid-attributes.stderr b/tests/ui/proc-macro/invalid-attributes.stderr index fe411fa5e1f..11c182ee03a 100644 --- a/tests/ui/proc-macro/invalid-attributes.stderr +++ b/tests/ui/proc-macro/invalid-attributes.stderr @@ -1,38 +1,57 @@ -error: malformed `proc_macro` attribute input +error[E0565]: malformed `proc_macro` attribute input --> $DIR/invalid-attributes.rs:10:1 | LL | #[proc_macro = "test"] - | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` + | ^^^^^^^^^^^^^--------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro]` -error: malformed `proc_macro` attribute input - --> $DIR/invalid-attributes.rs:13:1 +error[E0565]: malformed `proc_macro` attribute input + --> $DIR/invalid-attributes.rs:15:1 | LL | #[proc_macro()] - | ^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` + | ^^^^^^^^^^^^--^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro]` -error: malformed `proc_macro` attribute input - --> $DIR/invalid-attributes.rs:16:1 +error[E0565]: malformed `proc_macro` attribute input + --> $DIR/invalid-attributes.rs:20:1 | LL | #[proc_macro(x)] - | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` + | ^^^^^^^^^^^^---^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro]` -error: malformed `proc_macro_attribute` attribute input - --> $DIR/invalid-attributes.rs:19:1 +error[E0565]: malformed `proc_macro_attribute` attribute input + --> $DIR/invalid-attributes.rs:25:1 | LL | #[proc_macro_attribute = "test"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` + | ^^^^^^^^^^^^^^^^^^^^^^^--------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_attribute]` -error: malformed `proc_macro_attribute` attribute input - --> $DIR/invalid-attributes.rs:22:1 +error[E0565]: malformed `proc_macro_attribute` attribute input + --> $DIR/invalid-attributes.rs:30:1 | LL | #[proc_macro_attribute()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` + | ^^^^^^^^^^^^^^^^^^^^^^--^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_attribute]` -error: malformed `proc_macro_attribute` attribute input - --> $DIR/invalid-attributes.rs:25:1 +error[E0565]: malformed `proc_macro_attribute` attribute input + --> $DIR/invalid-attributes.rs:35:1 | LL | #[proc_macro_attribute(x)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` + | ^^^^^^^^^^^^^^^^^^^^^^---^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[proc_macro_attribute]` error: aborting due to 6 previous errors +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/process/nofile-limit.rs b/tests/ui/process/nofile-limit.rs index dafc982607c..64777b51425 100644 --- a/tests/ui/process/nofile-limit.rs +++ b/tests/ui/process/nofile-limit.rs @@ -7,6 +7,8 @@ //@ only-linux //@ no-prefer-dynamic //@ compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static +//@ ignore-backends: gcc + #![feature(exit_status_error)] #![feature(rustc_private)] extern crate libc; diff --git a/tests/ui/process/println-with-broken-pipe.rs b/tests/ui/process/println-with-broken-pipe.rs index fbac9b6cd95..58b83a2dd9a 100644 --- a/tests/ui/process/println-with-broken-pipe.rs +++ b/tests/ui/process/println-with-broken-pipe.rs @@ -5,6 +5,7 @@ //@ ignore-fuchsia //@ ignore-horizon //@ ignore-android +//@ ignore-backends: gcc //@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC" //@ compile-flags: -Zon-broken-pipe=error diff --git a/tests/ui/issues/issue-67552.rs b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.rs index 53f0e931d60..0875d385ddc 100644 --- a/tests/ui/issues/issue-67552.rs +++ b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.rs @@ -29,3 +29,5 @@ where //~^ ERROR reached the recursion limit while instantiating } } + +// https://github.com/rust-lang/rust/issues/67552 diff --git a/tests/ui/issues/issue-67552.stderr b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.stderr index def0a29f3e5..fe005984fab 100644 --- a/tests/ui/issues/issue-67552.stderr +++ b/tests/ui/recursion/recursive-impl-trait-iterator-by-ref-67552.stderr @@ -1,17 +1,17 @@ error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut ...>` - --> $DIR/issue-67552.rs:28:9 + --> $DIR/recursive-impl-trait-iterator-by-ref-67552.rs:28:9 | LL | rec(identity(&mut it)) | ^^^^^^^^^^^^^^^^^^^^^^ | note: `rec` defined here - --> $DIR/issue-67552.rs:21:1 + --> $DIR/recursive-impl-trait-iterator-by-ref-67552.rs:21:1 | LL | / fn rec<T>(mut it: T) LL | | where LL | | T: Iterator, | |________________^ - = note: the full type name has been written to '$TEST_BUILD_DIR/issue-67552.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/recursive-impl-trait-iterator-by-ref-67552.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-24353.rs b/tests/ui/return/early-return-with-unreachable-code-24353.rs index 369fc238d11..13add4652d9 100644 --- a/tests/ui/issues/issue-24353.rs +++ b/tests/ui/return/early-return-with-unreachable-code-24353.rs @@ -6,3 +6,5 @@ fn main() { let x = (); x } + +// https://github.com/rust-lang/rust/issues/24353 diff --git a/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs b/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs index bd62a644785..b1df1b191bc 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc //@ revisions: default mir-opt //@[mir-opt] compile-flags: -Zmir-opt-level=4 diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.rs new file mode 100644 index 00000000000..9d86ebc5331 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.rs @@ -0,0 +1,14 @@ +// gate-test-if_let_guard + +fn main() { + macro_rules! use_expr { + ($e:expr) => { + match () { + () if $e => {} + _ => {} + } + } + } + use_expr!(let 0 = 1); + //~^ ERROR no rules expected keyword `let` +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.stderr new file mode 100644 index 00000000000..411fde890a1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate-macro.stderr @@ -0,0 +1,17 @@ +error: no rules expected keyword `let` + --> $DIR/feature-gate-macro.rs:12:15 + | +LL | macro_rules! use_expr { + | --------------------- when calling this macro +... +LL | use_expr!(let 0 = 1); + | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> $DIR/feature-gate-macro.rs:5:10 + | +LL | ($e:expr) => { + | ^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index b1e305834cb..eb9e5dff37e 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -64,8 +64,6 @@ fn _macros() { //~^ ERROR `if let` guards are experimental _ => {} } - use_expr!(let 0 = 1); - //~^ ERROR no rules expected keyword `let` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr index 19d1f4b0a57..759f1478350 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -149,21 +149,6 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if` and `while` expressions = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: no rules expected keyword `let` - --> $DIR/feature-gate.rs:67:15 - | -LL | macro_rules! use_expr { - | --------------------- when calling this macro -... -LL | use_expr!(let 0 = 1); - | ^^^ no rules expected this token in macro call - | -note: while trying to match meta-variable `$e:expr` - --> $DIR/feature-gate.rs:48:10 - | -LL | ($e:expr) => { - | ^^^^^^^ - error[E0658]: `if let` guards are experimental --> $DIR/feature-gate.rs:7:12 | @@ -230,6 +215,6 @@ LL | () if let 0 = 1 => {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` -error: aborting due to 20 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/runtime/on-broken-pipe/child-processes.rs b/tests/ui/runtime/on-broken-pipe/child-processes.rs index 0da2347481b..c0c8ad4e2f5 100644 --- a/tests/ui/runtime/on-broken-pipe/child-processes.rs +++ b/tests/ui/runtime/on-broken-pipe/child-processes.rs @@ -1,6 +1,7 @@ //@ revisions: default error kill inherit //@ ignore-cross-compile because aux-bin does not yet support it //@ only-unix because SIGPIPE is a unix thing +//@ ignore-backends: gcc //@ run-pass //@ aux-bin:assert-sigpipe-disposition.rs //@ aux-crate:sigpipe_utils=sigpipe-utils.rs diff --git a/tests/ui/runtime/rt-explody-panic-payloads.rs b/tests/ui/runtime/rt-explody-panic-payloads.rs index d564a26ca73..1d5795f8e86 100644 --- a/tests/ui/runtime/rt-explody-panic-payloads.rs +++ b/tests/ui/runtime/rt-explody-panic-payloads.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-subprocess +//@ ignore-backends: gcc use std::env; use std::process::Command; diff --git a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs index f4f383e008a..fad57198dfb 100644 --- a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs +++ b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs @@ -6,6 +6,7 @@ //@ edition: 2021 //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu +//@ ignore-backends: gcc //@ build-pass trait Iterable { diff --git a/tests/ui/sanitizer/cfi/async-closures.rs b/tests/ui/sanitizer/cfi/async-closures.rs index 351853ab1a7..9b099263000 100644 --- a/tests/ui/sanitizer/cfi/async-closures.rs +++ b/tests/ui/sanitizer/cfi/async-closures.rs @@ -4,6 +4,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs index 99c12d72eb5..a881c6b92b2 100644 --- a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs +++ b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs @@ -2,6 +2,7 @@ //@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu +//@ ignore-backends: gcc //@ build-pass // See comment below for why this test exists. diff --git a/tests/ui/sanitizer/cfi/closures.rs b/tests/ui/sanitizer/cfi/closures.rs index 424e70560db..fc9718faa28 100644 --- a/tests/ui/sanitizer/cfi/closures.rs +++ b/tests/ui/sanitizer/cfi/closures.rs @@ -3,6 +3,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/cfi/complex-receiver.rs b/tests/ui/sanitizer/cfi/complex-receiver.rs index c7b45a775ca..aac44c33227 100644 --- a/tests/ui/sanitizer/cfi/complex-receiver.rs +++ b/tests/ui/sanitizer/cfi/complex-receiver.rs @@ -5,6 +5,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/cfi/coroutine.rs b/tests/ui/sanitizer/cfi/coroutine.rs index 39a754f1036..084a521f597 100644 --- a/tests/ui/sanitizer/cfi/coroutine.rs +++ b/tests/ui/sanitizer/cfi/coroutine.rs @@ -3,6 +3,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ edition: 2024 //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi diff --git a/tests/ui/sanitizer/cfi/drop-in-place.rs b/tests/ui/sanitizer/cfi/drop-in-place.rs index 8ce2c432602..160338a5b54 100644 --- a/tests/ui/sanitizer/cfi/drop-in-place.rs +++ b/tests/ui/sanitizer/cfi/drop-in-place.rs @@ -2,6 +2,7 @@ // // FIXME(#122848): Remove only-linux when fixed. //@ only-linux +//@ ignore-backends: gcc //@ needs-sanitizer-cfi //@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi //@ run-pass diff --git a/tests/ui/sanitizer/cfi/drop-no-principal.rs b/tests/ui/sanitizer/cfi/drop-no-principal.rs index c1c88c8c71c..e3a46fe9d75 100644 --- a/tests/ui/sanitizer/cfi/drop-no-principal.rs +++ b/tests/ui/sanitizer/cfi/drop-no-principal.rs @@ -3,6 +3,7 @@ //@ needs-sanitizer-cfi // FIXME(#122848) Remove only-linux once OSX CFI binaries works //@ only-linux +//@ ignore-backends: gcc //@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi //@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 // FIXME(#118761) Should be run-pass once the labels on drop are compatible. diff --git a/tests/ui/sanitizer/cfi/fn-ptr.rs b/tests/ui/sanitizer/cfi/fn-ptr.rs index 505b4b8e7f0..d3209c62ddf 100644 --- a/tests/ui/sanitizer/cfi/fn-ptr.rs +++ b/tests/ui/sanitizer/cfi/fn-ptr.rs @@ -3,6 +3,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/cfi/self-ref.rs b/tests/ui/sanitizer/cfi/self-ref.rs index 3b524ac661c..b93d49296b6 100644 --- a/tests/ui/sanitizer/cfi/self-ref.rs +++ b/tests/ui/sanitizer/cfi/self-ref.rs @@ -3,6 +3,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/cfi/sized-associated-ty.rs b/tests/ui/sanitizer/cfi/sized-associated-ty.rs index f5b4e22e9d9..eefc3e2e9db 100644 --- a/tests/ui/sanitizer/cfi/sized-associated-ty.rs +++ b/tests/ui/sanitizer/cfi/sized-associated-ty.rs @@ -4,6 +4,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/cfi/supertraits.rs b/tests/ui/sanitizer/cfi/supertraits.rs index f80b3169188..f5a984b9583 100644 --- a/tests/ui/sanitizer/cfi/supertraits.rs +++ b/tests/ui/sanitizer/cfi/supertraits.rs @@ -3,6 +3,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/cfi/virtual-auto.rs b/tests/ui/sanitizer/cfi/virtual-auto.rs index 6971d516a20..e6f2ebd4b2c 100644 --- a/tests/ui/sanitizer/cfi/virtual-auto.rs +++ b/tests/ui/sanitizer/cfi/virtual-auto.rs @@ -3,6 +3,7 @@ //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux +//@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static diff --git a/tests/ui/sanitizer/kcfi-mangling.rs b/tests/ui/sanitizer/kcfi-mangling.rs index fde7b5451b6..ba36dc184ec 100644 --- a/tests/ui/sanitizer/kcfi-mangling.rs +++ b/tests/ui/sanitizer/kcfi-mangling.rs @@ -4,6 +4,7 @@ //@ no-prefer-dynamic //@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0 //@ build-pass +//@ ignore-backends: gcc trait Foo { fn foo(&self); diff --git a/tests/ui/self-profile/pretty_print_no_ice.rs b/tests/ui/self-profile/pretty_print_no_ice.rs new file mode 100644 index 00000000000..71b15e82650 --- /dev/null +++ b/tests/ui/self-profile/pretty_print_no_ice.rs @@ -0,0 +1,14 @@ +// Checks that when we use `-Zself-profile-events=args`, it is possible to pretty print paths +// using `trimmed_def_paths` even without producing diagnostics. +// +// Issue: <https://github.com/rust-lang/rust/issues/144457>. + +//@ compile-flags: -Zself-profile={{build-base}} -Zself-profile-events=args +//@ build-pass + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::Relaxed; + +fn main() { + AtomicUsize::new(0).load(Relaxed); +} diff --git a/tests/ui/self/self_type_keyword.rs b/tests/ui/self/self_type_keyword.rs index 96d24715edb..bd051279a72 100644 --- a/tests/ui/self/self_type_keyword.rs +++ b/tests/ui/self/self_type_keyword.rs @@ -18,8 +18,6 @@ pub fn main() { //~| ERROR cannot find unit struct, unit variant or constant `Self` ref mut Self => (), //~^ ERROR expected identifier, found keyword `Self` - Self!() => (), - //~^ ERROR cannot find macro `Self` in this scope Foo { Self } => (), //~^ ERROR expected identifier, found keyword `Self` //~| ERROR mismatched types diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr index f9cde810cad..f22d04bb227 100644 --- a/tests/ui/self/self_type_keyword.stderr +++ b/tests/ui/self/self_type_keyword.stderr @@ -36,35 +36,29 @@ LL | ref mut Self => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:23:15 + --> $DIR/self_type_keyword.rs:21:15 | LL | Foo { Self } => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:31:26 + --> $DIR/self_type_keyword.rs:29:26 | LL | extern crate core as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:36:32 + --> $DIR/self_type_keyword.rs:34:32 | LL | use std::option::Option as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:41:11 + --> $DIR/self_type_keyword.rs:39:11 | LL | trait Self {} | ^^^^ expected identifier, found keyword -error: cannot find macro `Self` in this scope - --> $DIR/self_type_keyword.rs:21:9 - | -LL | Self!() => (), - | ^^^^ - error[E0531]: cannot find unit struct, unit variant or constant `Self` in this scope --> $DIR/self_type_keyword.rs:16:13 | @@ -86,7 +80,7 @@ LL | struct Bar<'Self>; = help: consider removing `'Self`, referring to it in a field, or using a marker such as `PhantomData` error[E0308]: mismatched types - --> $DIR/self_type_keyword.rs:23:9 + --> $DIR/self_type_keyword.rs:21:9 | LL | match 15 { | -- this expression has type `{integer}` @@ -95,12 +89,12 @@ LL | Foo { Self } => (), | ^^^^^^^^^^^^ expected integer, found `Foo` error[E0026]: struct `Foo` does not have a field named `Self` - --> $DIR/self_type_keyword.rs:23:15 + --> $DIR/self_type_keyword.rs:21:15 | LL | Foo { Self } => (), | ^^^^ struct `Foo` does not have this field -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors Some errors have detailed explanations: E0026, E0308, E0392, E0531. For more information about an error, try `rustc --explain E0026`. diff --git a/tests/ui/self/self_type_macro_name.rs b/tests/ui/self/self_type_macro_name.rs new file mode 100644 index 00000000000..b92b23b3b4e --- /dev/null +++ b/tests/ui/self/self_type_macro_name.rs @@ -0,0 +1,6 @@ +pub fn main() { + match 15 { + Self!() => (), + //~^ ERROR cannot find macro `Self` in this scope + } +} diff --git a/tests/ui/self/self_type_macro_name.stderr b/tests/ui/self/self_type_macro_name.stderr new file mode 100644 index 00000000000..25f766b758c --- /dev/null +++ b/tests/ui/self/self_type_macro_name.stderr @@ -0,0 +1,8 @@ +error: cannot find macro `Self` in this scope + --> $DIR/self_type_macro_name.rs:3:9 + | +LL | Self!() => (), + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs index bf38a8b1720..09f5d41a87c 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -1,4 +1,6 @@ //@ run-pass +//@ ignore-backends: gcc + #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] diff --git a/tests/ui/simd/intrinsic/generic-as.rs b/tests/ui/simd/intrinsic/generic-as.rs index f9ed416b6ff..bba712e6296 100644 --- a/tests/ui/simd/intrinsic/generic-as.rs +++ b/tests/ui/simd/intrinsic/generic-as.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![feature(repr_simd, core_intrinsics)] diff --git a/tests/ui/simd/issue-17170.rs b/tests/ui/simd/issue-17170.rs index 2d13962843c..508f480a58d 100644 --- a/tests/ui/simd/issue-17170.rs +++ b/tests/ui/simd/issue-17170.rs @@ -1,4 +1,6 @@ //@ run-pass +//@ ignore-backends: gcc + #![feature(repr_simd)] #[repr(simd)] diff --git a/tests/ui/simd/issue-39720.rs b/tests/ui/simd/issue-39720.rs index 09d6142c920..41617c744d6 100644 --- a/tests/ui/simd/issue-39720.rs +++ b/tests/ui/simd/issue-39720.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![feature(repr_simd, core_intrinsics)] diff --git a/tests/ui/simd/masked-load-store.rs b/tests/ui/simd/masked-load-store.rs index da32ba611c4..bc4307fb26d 100644 --- a/tests/ui/simd/masked-load-store.rs +++ b/tests/ui/simd/masked-load-store.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ run-pass #![feature(repr_simd, core_intrinsics)] diff --git a/tests/ui/simd/repr_packed.rs b/tests/ui/simd/repr_packed.rs index f0c6de7c402..9cf679dc432 100644 --- a/tests/ui/simd/repr_packed.rs +++ b/tests/ui/simd/repr_packed.rs @@ -1,3 +1,4 @@ +//@ ignore-backends: gcc //@ run-pass #![feature(repr_simd, core_intrinsics)] diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs index b9af591d1b9..991fe0d8933 100644 --- a/tests/ui/simd/simd-bitmask-notpow2.rs +++ b/tests/ui/simd/simd-bitmask-notpow2.rs @@ -2,6 +2,8 @@ // FIXME: broken codegen on big-endian (https://github.com/rust-lang/rust/issues/127205) // This should be merged into `simd-bitmask` once that's fixed. //@ ignore-endian-big +//@ ignore-backends: gcc + #![feature(repr_simd, core_intrinsics)] #[path = "../../auxiliary/minisimd.rs"] diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/sized/relaxing-default-bound-error-37534.rs index 63f6479ae2e..d30e9f92ce9 100644 --- a/tests/ui/issues/issue-37534.rs +++ b/tests/ui/sized/relaxing-default-bound-error-37534.rs @@ -3,3 +3,5 @@ struct Foo<T: ?Hash> {} //~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} + +// https://github.com/rust-lang/rust/issues/37534 diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/sized/relaxing-default-bound-error-37534.stderr index 08607354203..8b9597f33e3 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/sized/relaxing-default-bound-error-37534.stderr @@ -1,5 +1,5 @@ error[E0404]: expected trait, found derive macro `Hash` - --> $DIR/issue-37534.rs:1:16 + --> $DIR/relaxing-default-bound-error-37534.rs:1:16 | LL | struct Foo<T: ?Hash> {} | ^^^^ not a trait @@ -10,7 +10,7 @@ LL + use std::hash::Hash; | error: bound modifier `?` can only be applied to `Sized` - --> $DIR/issue-37534.rs:1:15 + --> $DIR/relaxing-default-bound-error-37534.rs:1:15 | LL | struct Foo<T: ?Hash> {} | ^^^^^ diff --git a/tests/ui/static/issue-24446.rs b/tests/ui/static/issue-24446.rs index 830e373c189..ffd6dfabc28 100644 --- a/tests/ui/static/issue-24446.rs +++ b/tests/ui/static/issue-24446.rs @@ -1,8 +1,6 @@ fn main() { static foo: dyn Fn() -> u32 = || -> u32 { //~^ ERROR the size for values of type - //~| ERROR cannot be shared between threads safely - //~| ERROR mismatched types 0 }; } diff --git a/tests/ui/static/issue-24446.stderr b/tests/ui/static/issue-24446.stderr index ed195634f12..497ce8ccfb6 100644 --- a/tests/ui/static/issue-24446.stderr +++ b/tests/ui/static/issue-24446.stderr @@ -1,12 +1,3 @@ -error[E0277]: `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely - --> $DIR/issue-24446.rs:2:17 - | -LL | static foo: dyn Fn() -> u32 = || -> u32 { - | ^^^^^^^^^^^^^^^ `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `(dyn Fn() -> u32 + 'static)` - = note: shared static variables must have a type that implements `Sync` - error[E0277]: the size for values of type `(dyn Fn() -> u32 + 'static)` cannot be known at compilation time --> $DIR/issue-24446.rs:2:5 | @@ -16,19 +7,6 @@ LL | static foo: dyn Fn() -> u32 = || -> u32 { = help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)` = note: statics and constants must have a statically known size -error[E0308]: mismatched types - --> $DIR/issue-24446.rs:2:35 - | -LL | static foo: dyn Fn() -> u32 = || -> u32 { - | ___________________________________^ -... | -LL | | }; - | |_____^ expected `dyn Fn`, found closure - | - = note: expected trait object `(dyn Fn() -> u32 + 'static)` - found closure `{closure@$DIR/issue-24446.rs:2:35: 2:44}` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/static/static-items-cant-move.stderr b/tests/ui/static/static-items-cant-move.stderr index 1361e7089e8..7c806613c5c 100644 --- a/tests/ui/static/static-items-cant-move.stderr +++ b/tests/ui/static/static-items-cant-move.stderr @@ -3,6 +3,15 @@ error[E0507]: cannot move out of static item `BAR` | LL | test(BAR); | ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/static-items-cant-move.rs:5:1 + | +LL | struct Foo { + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | test(BAR); + | --- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs index 6cc0a65f77d..1921b2c99a3 100644 --- a/tests/ui/statics/const_generics.rs +++ b/tests/ui/statics/const_generics.rs @@ -3,6 +3,7 @@ //! This is not an intentional guarantee, it just describes the status quo. //@ run-pass +//@ ignore-backends: gcc // With optimizations, LLVM will deduplicate the constant `X` whose // value is `&42` to just be a reference to the static. This is correct, // but obscures the issue we're trying to show. diff --git a/tests/ui/issues/issue-11267.rs b/tests/ui/structs/mutable-unit-struct-borrow-11267.rs index 036ad1d54ed..d96c4a4e79b 100644 --- a/tests/ui/issues/issue-11267.rs +++ b/tests/ui/structs/mutable-unit-struct-borrow-11267.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11267 + //@ run-pass // Tests that unary structs can be mutably borrowed. diff --git a/tests/ui/issues/issue-3389.rs b/tests/ui/structs/trie-node-structure-usage-3389.rs index 4e73a2cf001..1518e107944 100644 --- a/tests/ui/issues/issue-3389.rs +++ b/tests/ui/structs/trie-node-structure-usage-3389.rs @@ -24,3 +24,5 @@ pub fn main() { print_str_vector(node.content.clone()); } + +// https://github.com/rust-lang/rust/issues/3389 diff --git a/tests/ui/suggestions/enum-method-probe.fixed b/tests/ui/suggestions/enum-method-probe.fixed index e097fa8cc1d..b7fd6f112d5 100644 --- a/tests/ui/suggestions/enum-method-probe.fixed +++ b/tests/ui/suggestions/enum-method-probe.fixed @@ -56,4 +56,11 @@ fn test_option_in_unit_return() { //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` } +fn test_option_private_method() { + let res: Option<_> = Some(vec![1, 2, 3]); + res.expect("REASON").len(); + //~^ ERROR method `len` is private + //~| HELP consider using `Option::expect` to unwrap the `Vec<{integer}>` value, panicking if the value is an `Option::None` +} + fn main() {} diff --git a/tests/ui/suggestions/enum-method-probe.rs b/tests/ui/suggestions/enum-method-probe.rs index 665ee7d0aaa..cbb819b7c8c 100644 --- a/tests/ui/suggestions/enum-method-probe.rs +++ b/tests/ui/suggestions/enum-method-probe.rs @@ -56,4 +56,11 @@ fn test_option_in_unit_return() { //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` } +fn test_option_private_method() { + let res: Option<_> = Some(vec![1, 2, 3]); + res.len(); + //~^ ERROR method `len` is private + //~| HELP consider using `Option::expect` to unwrap the `Vec<{integer}>` value, panicking if the value is an `Option::None` +} + fn main() {} diff --git a/tests/ui/suggestions/enum-method-probe.stderr b/tests/ui/suggestions/enum-method-probe.stderr index 6ed14984f47..e66973d9d95 100644 --- a/tests/ui/suggestions/enum-method-probe.stderr +++ b/tests/ui/suggestions/enum-method-probe.stderr @@ -94,6 +94,23 @@ help: consider using `Option::expect` to unwrap the `Foo` value, panicking if th LL | res.expect("REASON").get(); | +++++++++++++++++ -error: aborting due to 6 previous errors +error[E0624]: method `len` is private + --> $DIR/enum-method-probe.rs:61:9 + | +LL | res.len(); + | ^^^ private method + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: private method defined here + | +note: the method `len` exists on the type `Vec<{integer}>` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL +help: consider using `Option::expect` to unwrap the `Vec<{integer}>` value, panicking if the value is an `Option::None` + | +LL | res.expect("REASON").len(); + | +++++++++++++++++ + +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0599`. +Some errors have detailed explanations: E0599, E0624. +For more information about an error, try `rustc --explain E0599`. diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr index 436441d6f1b..c73e874b403 100644 --- a/tests/ui/suggestions/option-content-move2.stderr +++ b/tests/ui/suggestions/option-content-move2.stderr @@ -13,6 +13,15 @@ LL | move || { LL | LL | var = Some(NotCopyable); | --- variable moved due to use in closure + | +note: if `NotCopyable` implemented `Clone`, you could clone the value + --> $DIR/option-content-move2.rs:1:1 + | +LL | struct NotCopyable; + | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | var = Some(NotCopyable); + | --- you could clone this value error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure --> $DIR/option-content-move2.rs:21:9 diff --git a/tests/ui/issues/issue-39089.rs b/tests/ui/trait-bounds/for-binder-placement-error-39089.rs index 822c47503af..47976bdfff4 100644 --- a/tests/ui/issues/issue-39089.rs +++ b/tests/ui/trait-bounds/for-binder-placement-error-39089.rs @@ -2,3 +2,5 @@ fn f<T: ?for<'a> Sized>() {} //~^ ERROR `for<...>` binder should be placed before trait bound modifiers fn main() {} + +// https://github.com/rust-lang/rust/issues/39089 diff --git a/tests/ui/issues/issue-39089.stderr b/tests/ui/trait-bounds/for-binder-placement-error-39089.stderr index a81010aedff..12fcbc5757f 100644 --- a/tests/ui/issues/issue-39089.stderr +++ b/tests/ui/trait-bounds/for-binder-placement-error-39089.stderr @@ -1,5 +1,5 @@ error: `for<...>` binder should be placed before trait bound modifiers - --> $DIR/issue-39089.rs:1:13 + --> $DIR/for-binder-placement-error-39089.rs:1:13 | LL | fn f<T: ?for<'a> Sized>() {} | - ^^^^ diff --git a/tests/ui/issues/issue-10456.rs b/tests/ui/traits/blanket-impl-trait-object-10456.rs index 51c740fd729..f8421431774 100644 --- a/tests/ui/issues/issue-10456.rs +++ b/tests/ui/traits/blanket-impl-trait-object-10456.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10456 + //@ check-pass pub struct Foo; diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.rs b/tests/ui/traits/bound/on-structs-and-enums-static.rs index d734893dd7c..61e8e2ace60 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-static.rs +++ b/tests/ui/traits/bound/on-structs-and-enums-static.rs @@ -6,9 +6,7 @@ struct Foo<T:Trait> { x: T, } -static X: Foo<usize> = Foo { -//~^ ERROR E0277 -//~| ERROR E0277 +static X: Foo<usize> = Foo { //~ ERROR E0277 x: 1, //~ ERROR: E0277 }; diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.stderr b/tests/ui/traits/bound/on-structs-and-enums-static.stderr index 42ebcc07571..1413422794a 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-static.stderr +++ b/tests/ui/traits/bound/on-structs-and-enums-static.stderr @@ -15,29 +15,11 @@ note: required by a bound in `Foo` LL | struct Foo<T:Trait> { | ^^^^^ required by this bound in `Foo` -error[E0277]: the trait bound `usize: Trait` is not satisfied - --> $DIR/on-structs-and-enums-static.rs:9:11 - | -LL | static X: Foo<usize> = Foo { - | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` - | -help: this trait has no implementations, consider adding one - --> $DIR/on-structs-and-enums-static.rs:1:1 - | -LL | trait Trait { - | ^^^^^^^^^^^ -note: required by a bound in `Foo` - --> $DIR/on-structs-and-enums-static.rs:5:14 - | -LL | struct Foo<T:Trait> { - | ^^^^^ required by this bound in `Foo` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0277]: the trait bound `usize: Trait` is not satisfied - --> $DIR/on-structs-and-enums-static.rs:12:8 +error[E0277]: the trait bound `{integer}: Trait` is not satisfied + --> $DIR/on-structs-and-enums-static.rs:10:8 | LL | x: 1, - | ^ the trait `Trait` is not implemented for `usize` + | ^ the trait `Trait` is not implemented for `{integer}` | help: this trait has no implementations, consider adding one --> $DIR/on-structs-and-enums-static.rs:1:1 @@ -50,6 +32,6 @@ note: required by a bound in `Foo` LL | struct Foo<T:Trait> { | ^^^^^ required by this bound in `Foo` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr index 9c49ee56b0f..ff803ff889b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:33:5 + --> $DIR/const-drop-fail.rs:34:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +8,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:35:5 + --> $DIR/const-drop-fail.rs:36:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,7 +23,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr index 9c49ee56b0f..ff803ff889b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:33:5 + --> $DIR/const-drop-fail.rs:34:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +8,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:35:5 + --> $DIR/const-drop-fail.rs:36:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,7 +23,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr index 9c49ee56b0f..ff803ff889b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:33:5 + --> $DIR/const-drop-fail.rs:34:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +8,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:35:5 + --> $DIR/const-drop-fail.rs:36:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,7 +23,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr index 9c49ee56b0f..ff803ff889b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:33:5 + --> $DIR/const-drop-fail.rs:34:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +8,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:35:5 + --> $DIR/const-drop-fail.rs:36:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,7 +23,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:24:19 + --> $DIR/const-drop-fail.rs:25:19 | LL | const fn check<T: [const] Destruct>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` diff --git a/tests/ui/traits/const-traits/const-drop-fail.rs b/tests/ui/traits/const-traits/const-drop-fail.rs index 4513d71f613..b74716f0061 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.rs +++ b/tests/ui/traits/const-traits/const-drop-fail.rs @@ -1,6 +1,7 @@ //@[new_precise] compile-flags: -Znext-solver //@[new_stock] compile-flags: -Znext-solver //@ revisions: new_stock old_stock new_precise old_precise +//@ ignore-backends: gcc #![feature(const_trait_impl, const_destruct)] #![cfg_attr(any(new_precise, old_precise), feature(const_precise_live_drops))] diff --git a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs index a5f6ae198f6..ee04f74c8a6 100644 --- a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs +++ b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs @@ -13,7 +13,7 @@ macro_rules! check { compile_error!("ty"); }; (const $Trait:path) => {}; - ([const] $Trait:path) => {}; + ([const] $Trait:path) => { [const] Trait }; } check! { const Trait } diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs index 3dcdb0cad94..35e964eacec 100644 --- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs +++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs @@ -4,18 +4,19 @@ // Setting the edition to 2018 since we don't regress `demo! { dyn const }` in Rust <2018. //@ edition:2018 +trait Trait {} + macro_rules! demo { - ($ty:ty) => { compile_error!("ty"); }; - //~^ ERROR ty - //~| ERROR ty - (impl $c:ident Trait) => {}; - (dyn $c:ident Trait) => {}; + (impl $c:ident Trait) => { impl $c Trait {} }; + //~^ ERROR inherent + //~| WARN trait objects without an explicit `dyn` are deprecated + //~| WARN this is accepted in the current edition + (dyn $c:ident Trait) => { dyn $c Trait {} }; //~ ERROR macro expansion } demo! { impl const Trait } //~^ ERROR const trait impls are experimental demo! { dyn const Trait } -//~^ ERROR const trait impls are experimental fn main() {} diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr index b500e4858d1..af160a45f3e 100644 --- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr +++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr @@ -1,27 +1,31 @@ -error: ty - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:8:19 +error: macro expansion ignores keyword `dyn` and any tokens following + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:14:31 | -LL | ($ty:ty) => { compile_error!("ty"); }; - | ^^^^^^^^^^^^^^^^^^^^ +LL | (dyn $c:ident Trait) => { dyn $c Trait {} }; + | ^^^ ... -LL | demo! { impl const Trait } - | -------------------------- in this macro invocation +LL | demo! { dyn const Trait } + | ------------------------- caused by the macro expansion here | - = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: the usage of `demo!` is likely invalid in item context -error: ty - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:8:19 +error: inherent impls cannot be `const` + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40 | -LL | ($ty:ty) => { compile_error!("ty"); }; - | ^^^^^^^^^^^^^^^^^^^^ +LL | (impl $c:ident Trait) => { impl $c Trait {} }; + | ^^^^^ inherent impl for this type ... -LL | demo! { dyn const Trait } - | ------------------------- in this macro invocation +LL | demo! { impl const Trait } + | -------------------------- + | | | + | | `const` because of this + | in this macro invocation | + = note: only trait implementations may be annotated with `const` = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: const trait impls are experimental - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:15:14 + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:17:14 | LL | demo! { impl const Trait } | ^^^^^ @@ -30,16 +34,24 @@ LL | demo! { impl const Trait } = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: const trait impls are experimental - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:18:13 +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40 | -LL | demo! { dyn const Trait } - | ^^^^^ +LL | (impl $c:ident Trait) => { impl $c Trait {} }; + | ^^^^^ +... +LL | demo! { impl const Trait } + | -------------------------- in this macro invocation | - = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information - = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html> + = note: `#[warn(bare_trait_objects)]` on by default + = note: this warning originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might have intended to implement this trait for a given type + | +LL | (impl $c:ident Trait) => { impl $c Trait for /* Type */ {} }; + | ++++++++++++++ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/issues/issue-23281.rs b/tests/ui/traits/dyn-trait-size-error-23281.rs index 72716896426..8e44b8c8799 100644 --- a/tests/ui/issues/issue-23281.rs +++ b/tests/ui/traits/dyn-trait-size-error-23281.rs @@ -10,3 +10,5 @@ struct Vec<T> { } fn main() {} + +// https://github.com/rust-lang/rust/issues/23281 diff --git a/tests/ui/issues/issue-23281.stderr b/tests/ui/traits/dyn-trait-size-error-23281.stderr index ee079f2deec..d7b791a0452 100644 --- a/tests/ui/issues/issue-23281.stderr +++ b/tests/ui/traits/dyn-trait-size-error-23281.stderr @@ -1,17 +1,17 @@ error[E0277]: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time - --> $DIR/issue-23281.rs:4:27 + --> $DIR/dyn-trait-size-error-23281.rs:4:27 | LL | pub fn function(funs: Vec<dyn Fn() -> ()>) {} | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)` note: required by an implicit `Sized` bound in `Vec` - --> $DIR/issue-23281.rs:8:12 + --> $DIR/dyn-trait-size-error-23281.rs:8:12 | LL | struct Vec<T> { | ^ required by the implicit `Sized` requirement on this type parameter in `Vec` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` - --> $DIR/issue-23281.rs:8:12 + --> $DIR/dyn-trait-size-error-23281.rs:8:12 | LL | struct Vec<T> { | ^ this could be changed to `T: ?Sized`... diff --git a/tests/ui/issues/issue-10465.rs b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.rs index d899c3ffa91..d5a500900ff 100644 --- a/tests/ui/issues/issue-10465.rs +++ b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/10465 + pub mod a { pub trait A { fn foo(&self); diff --git a/tests/ui/issues/issue-10465.stderr b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.stderr index 0f46ebe505a..ffd8fd39250 100644 --- a/tests/ui/issues/issue-10465.stderr +++ b/tests/ui/traits/nested-mod-trait-method-lookup-leak-10465.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `foo` found for reference `&B` in the current scope - --> $DIR/issue-10465.rs:17:15 + --> $DIR/nested-mod-trait-method-lookup-leak-10465.rs:19:15 | LL | b.foo(); | ^^^ method not found in `&B` diff --git a/tests/ui/issues/issue-36839.rs b/tests/ui/traits/trait-associated-type-bounds-36839.rs index 654c0f6e4b5..156c063abc2 100644 --- a/tests/ui/issues/issue-36839.rs +++ b/tests/ui/traits/trait-associated-type-bounds-36839.rs @@ -19,3 +19,5 @@ impl<T> Broken for T { fn main() { let _m: &dyn Broken<Assoc=()> = &(); } + +// https://github.com/rust-lang/rust/issues/36839 diff --git a/tests/ui/issues/issue-5280.rs b/tests/ui/traits/trait-implementation-for-primitive-type-5280.rs index 66452c36776..72a4283bc7e 100644 --- a/tests/ui/issues/issue-5280.rs +++ b/tests/ui/traits/trait-implementation-for-primitive-type-5280.rs @@ -16,3 +16,5 @@ impl FontTableTagConversions for FontTableTag { pub fn main() { 5.tag_to_string(); } + +// https://github.com/rust-lang/rust/issues/5280 diff --git a/tests/ui/issues/issue-5321-immediates-with-bare-self.rs b/tests/ui/traits/trait-implementation-for-usize-5321.rs index cb35a641c5e..ab997b6627a 100644 --- a/tests/ui/issues/issue-5321-immediates-with-bare-self.rs +++ b/tests/ui/traits/trait-implementation-for-usize-5321.rs @@ -13,3 +13,5 @@ impl Fooable for usize { pub fn main() { 2.yes(); } + +// https://github.com/rust-lang/rust/issues/5321 diff --git a/tests/ui/issues/issue-21174.rs b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.rs index 07827425116..22cb379ffda 100644 --- a/tests/ui/issues/issue-21174.rs +++ b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.rs @@ -9,3 +9,5 @@ fn foo<'a, T: Trait<'a>>(value: T::A) { } fn main() { } + +// https://github.com/rust-lang/rust/issues/21174 diff --git a/tests/ui/issues/issue-21174.stderr b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.stderr index a6b75c91352..5c0cd91cee1 100644 --- a/tests/ui/issues/issue-21174.stderr +++ b/tests/ui/transmutability/transmute-between-associated-types-with-lifetimers-21174.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/issue-21174.rs:7:30 + --> $DIR/transmute-between-associated-types-with-lifetimers-21174.rs:7:30 | LL | let new: T::B = unsafe { std::mem::transmute(value) }; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/issues/issue-102964.rs b/tests/ui/type-alias/dummy-binder-102964.rs index 43ff2360076..6b6fa3ed5e3 100644 --- a/tests/ui/issues/issue-102964.rs +++ b/tests/ui/type-alias/dummy-binder-102964.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/102964 + use std::rc::Rc; type Foo<'a, T> = &'a dyn Fn(&T); type RcFoo<'a, T> = Rc<Foo<'a, T>>; diff --git a/tests/ui/issues/issue-102964.stderr b/tests/ui/type-alias/dummy-binder-102964.stderr index 0e2761f3f57..fc32cabaf71 100644 --- a/tests/ui/issues/issue-102964.stderr +++ b/tests/ui/type-alias/dummy-binder-102964.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-102964.rs:5:41 + --> $DIR/dummy-binder-102964.rs:7:41 | LL | fn bar_function<T>(function: Foo<T>) -> RcFoo<T> { | ------------ ^^^^^^^^ expected `Rc<&dyn Fn(&T)>`, found `()` diff --git a/tests/ui/issues/issue-11047.rs b/tests/ui/type-alias/static-method-type-alias-11047.rs index 6e1b2856afc..efb336fb4f7 100644 --- a/tests/ui/issues/issue-11047.rs +++ b/tests/ui/type-alias/static-method-type-alias-11047.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11047 + //@ run-pass // Test that static methods can be invoked on `type` aliases diff --git a/tests/ui/issues/issue-14382.rs b/tests/ui/type-inference/float-type-inference-unification-14382.rs index 74d938783ae..5bf497d2eab 100644 --- a/tests/ui/issues/issue-14382.rs +++ b/tests/ui/type-inference/float-type-inference-unification-14382.rs @@ -13,3 +13,5 @@ fn main() { let m : Matrix4<f32> = translate(x); println!("m: {:?}", m); } + +// https://github.com/rust-lang/rust/issues/14382 diff --git a/tests/ui/issues/issue-18952.rs b/tests/ui/unboxed-closures/fn-traits-overloading-arity-18952.rs index 9fdafb1ff4a..4e3bc9b671a 100644 --- a/tests/ui/issues/issue-18952.rs +++ b/tests/ui/unboxed-closures/fn-traits-overloading-arity-18952.rs @@ -54,3 +54,5 @@ fn main() { assert_eq!(foo(1, 1), (2, 2)); assert_eq!(foo(1, 1, 1), (4, 4, 4)); } + +// https://github.com/rust-lang/rust/issues/18952 diff --git a/tests/ui/issues/issue-22789.rs b/tests/ui/unboxed-closures/unboxed-closure-call-22789.rs index 95ebe6baaa3..0bc8bed0588 100644 --- a/tests/ui/issues/issue-22789.rs +++ b/tests/ui/unboxed-closures/unboxed-closure-call-22789.rs @@ -6,3 +6,5 @@ fn main() { let k = |x: i32| { x + 1 }; Fn::call(&k, (0,)); } + +// https://github.com/rust-lang/rust/issues/22789 diff --git a/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs index 2c2788a3e56..e439a82be5a 100644 --- a/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs +++ b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc // See https://github.com/rust-lang/rust/issues/135802 enum Void {} diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr index f8e9609cb1c..461ee407e2d 100644 --- a/tests/ui/union/union-borrow-move-parent-sibling.stderr +++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr @@ -31,6 +31,15 @@ LL | let a = u.x; | --- value moved here LL | let b = u.y; | ^^^ value used here after move + | +note: if `U` implemented `Clone`, you could clone the value + --> $DIR/union-borrow-move-parent-sibling.rs:43:1 + | +LL | union U { + | ^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.x; + | --- you could clone this value error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) --> $DIR/union-borrow-move-parent-sibling.rs:67:13 @@ -73,6 +82,15 @@ LL | let a = u.x; | --- value moved here LL | let b = u.y; | ^^^ value used here after move + | +note: if `U` implemented `Clone`, you could clone the value + --> $DIR/union-borrow-move-parent-sibling.rs:43:1 + | +LL | union U { + | ^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = u.x; + | --- you could clone this value error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`) --> $DIR/union-borrow-move-parent-sibling.rs:81:13 diff --git a/tests/ui/issues/issue-7246.rs b/tests/ui/unreachable-code/unreachable-bool-read-7246.rs index 7b16fa024f8..8bbaa102549 100644 --- a/tests/ui/issues/issue-7246.rs +++ b/tests/ui/unreachable-code/unreachable-bool-read-7246.rs @@ -9,3 +9,5 @@ pub unsafe fn g() { } pub fn main() {} + +// https://github.com/rust-lang/rust/issues/7246 diff --git a/tests/ui/issues/issue-7246.stderr b/tests/ui/unreachable-code/unreachable-bool-read-7246.stderr index 1fb6ab14e64..6072160cb5f 100644 --- a/tests/ui/issues/issue-7246.stderr +++ b/tests/ui/unreachable-code/unreachable-bool-read-7246.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/issue-7246.rs:7:5 + --> $DIR/unreachable-bool-read-7246.rs:7:5 | LL | return; | ------ any code following this expression is unreachable @@ -7,13 +7,13 @@ LL | if *ptr::null() {}; | ^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here - --> $DIR/issue-7246.rs:1:9 + --> $DIR/unreachable-bool-read-7246.rs:1:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ warning: dereferencing a null pointer - --> $DIR/issue-7246.rs:7:8 + --> $DIR/unreachable-bool-read-7246.rs:7:8 | LL | if *ptr::null() {}; | ^^^^^^^^^^^^ this code causes undefined behavior when executed diff --git a/tests/ui/unsafe-binders/moves.stderr b/tests/ui/unsafe-binders/moves.stderr index 0f976d9e845..bd480157077 100644 --- a/tests/ui/unsafe-binders/moves.stderr +++ b/tests/ui/unsafe-binders/moves.stderr @@ -16,6 +16,15 @@ LL | let binder: unsafe<> NotCopy = wrap_binder!(base); | ---- value moved here LL | drop(base); | ^^^^ value used here after move + | +note: if `NotCopyInner` implemented `Clone`, you could clone the value + --> $DIR/moves.rs:8:1 + | +LL | struct NotCopyInner; + | ^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let binder: unsafe<> NotCopy = wrap_binder!(base); + | ---- you could clone this value error[E0382]: use of moved value: `binder` --> $DIR/moves.rs:24:14 diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/unsafe/raw-pointer-field-access-error.rs index 0c34554c12d..04b45b2d3c6 100644 --- a/tests/ui/issues/issue-11004.rs +++ b/tests/ui/unsafe/raw-pointer-field-access-error.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11004 + use std::mem; struct A { x: i32, y: f64 } diff --git a/tests/ui/issues/issue-11004.stderr b/tests/ui/unsafe/raw-pointer-field-access-error.stderr index 6d157c91130..e9a205a5fa6 100644 --- a/tests/ui/issues/issue-11004.stderr +++ b/tests/ui/unsafe/raw-pointer-field-access-error.stderr @@ -1,5 +1,5 @@ error[E0609]: no field `x` on type `*mut A` - --> $DIR/issue-11004.rs:7:21 + --> $DIR/raw-pointer-field-access-error.rs:9:21 | LL | let x : i32 = n.x; | ^ unknown field @@ -10,7 +10,7 @@ LL | let x : i32 = (*n).x; | ++ + error[E0609]: no field `y` on type `*mut A` - --> $DIR/issue-11004.rs:8:21 + --> $DIR/raw-pointer-field-access-error.rs:10:21 | LL | let y : f64 = n.y; | ^ unknown field diff --git a/tests/ui/issues/issue-41229-ref-str.rs b/tests/ui/unsized/unsized-function-argument-41229.rs index fe5e6cd6ec5..9210431dc2f 100644 --- a/tests/ui/issues/issue-41229-ref-str.rs +++ b/tests/ui/unsized/unsized-function-argument-41229.rs @@ -2,3 +2,5 @@ pub fn example(ref s: str) {} //~^ ERROR the size for values of type fn main() {} + +// https://github.com/rust-lang/rust/issues/41229 diff --git a/tests/ui/issues/issue-41229-ref-str.stderr b/tests/ui/unsized/unsized-function-argument-41229.stderr index d4ef2a77725..326e5681f70 100644 --- a/tests/ui/issues/issue-41229-ref-str.stderr +++ b/tests/ui/unsized/unsized-function-argument-41229.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/issue-41229-ref-str.rs:1:23 + --> $DIR/unsized-function-argument-41229.rs:1:23 | LL | pub fn example(ref s: str) {} | ^^^ doesn't have a size known at compile-time diff --git a/tests/ui/use/use-after-move-implicity-coerced-object.stderr b/tests/ui/use/use-after-move-implicity-coerced-object.stderr index 35ede21717e..defaeef361b 100644 --- a/tests/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/tests/ui/use/use-after-move-implicity-coerced-object.stderr @@ -17,6 +17,14 @@ LL | fn push(&mut self, n: Box<dyn ToString + 'static>) { | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this method +note: if `Number` implemented `Clone`, you could clone the value + --> $DIR/use-after-move-implicity-coerced-object.rs:3:1 + | +LL | struct Number { + | ^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | l.push(n); + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/wf/wf-static-type.rs b/tests/ui/wf/wf-static-type.rs index 1980c5de40c..1c35e1daf44 100644 --- a/tests/ui/wf/wf-static-type.rs +++ b/tests/ui/wf/wf-static-type.rs @@ -9,8 +9,6 @@ struct NotCopy; static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; //~^ ERROR E0277 -//~| ERROR E0277 -//~| ERROR E0277 fn main() { } diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr index 53b90c69960..2fa8ae06c45 100644 --- a/tests/ui/wf/wf-static-type.stderr +++ b/tests/ui/wf/wf-static-type.stderr @@ -16,43 +16,6 @@ LL + #[derive(Copy)] LL | struct NotCopy; | -error[E0277]: the trait bound `NotCopy: Copy` is not satisfied - --> $DIR/wf-static-type.rs:10:13 - | -LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` - | - = note: required for `Option<NotCopy>` to implement `Copy` -note: required by a bound in `IsCopy` - --> $DIR/wf-static-type.rs:7:17 - | -LL | struct IsCopy<T:Copy> { t: T } - | ^^^^ required by this bound in `IsCopy` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider annotating `NotCopy` with `#[derive(Copy)]` - | -LL + #[derive(Copy)] -LL | struct NotCopy; - | - -error[E0277]: the trait bound `NotCopy: Copy` is not satisfied - --> $DIR/wf-static-type.rs:10:51 - | -LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^ the trait `Copy` is not implemented for `NotCopy` - | - = note: required for `Option<NotCopy>` to implement `Copy` -note: required by a bound in `IsCopy` - --> $DIR/wf-static-type.rs:7:17 - | -LL | struct IsCopy<T:Copy> { t: T } - | ^^^^ required by this bound in `IsCopy` -help: consider annotating `NotCopy` with `#[derive(Copy)]` - | -LL + #[derive(Copy)] -LL | struct NotCopy; - | - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/triagebot.toml b/triagebot.toml index 5b522a6617c..894f56df741 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -28,6 +28,7 @@ allow-unauthenticated = [ "llvm-*", "needs-fcp", "relnotes", + "release-blog-post", "requires-*", "regression-*", "rla-*", @@ -1096,7 +1097,7 @@ cc = ["@jieyouxu"] message = "The list of allowed third-party dependencies may have been modified! You must ensure that any new dependencies have compatible licenses before merging." cc = ["@davidtwco", "@wesleywiser"] -[mentions."src/tools/tidy/src/ext_tool_checks.rs"] +[mentions."src/tools/tidy/src/extra_checks"] message = "`tidy` extra checks were modified." cc = ["@lolbinarycat"] |
