diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 872c022373d45..27760dd7ea504 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -408,7 +408,7 @@ impl<'a> Drop for DiagnosticHandlers<'a> { fn report_inline_asm( cgcx: &CodegenContext, msg: String, - level: llvm::DiagnosticLevel, + severity: llvm::DiagnosticSeverity, cookie: u64, source: Option<(String, Vec)>, ) -> InlineAsmError { @@ -422,10 +422,10 @@ fn report_inline_asm( let hi = BytePos::from_u32((cookie >> 32) as u32); (lo, hi) }; - let level = match level { - llvm::DiagnosticLevel::Error => Level::Error, - llvm::DiagnosticLevel::Warning => Level::Warning(None), - llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, + let level = match severity { + llvm::DiagnosticSeverity::Error => Level::Error, + llvm::DiagnosticSeverity::Warning => Level::Warning(None), + llvm::DiagnosticSeverity::Note | llvm::DiagnosticSeverity::Remark => Level::Note, }; let msg = msg.trim_prefix("error: ").to_string(); InlineAsmError { lo, hi, msg, level, source } @@ -456,7 +456,7 @@ fn diagnostic_handler_callback_inner( shared_emitter.inline_asm_error(report_inline_asm( cgcx, inline.message, - inline.level, + inline.severity, inline.cookie, inline.source, )); @@ -479,21 +479,22 @@ fn diagnostic_handler_callback_inner( message: &opt.message, }); } - llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => { - let message = llvm::build_string(|s| unsafe { - llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) - }) - .expect("non-UTF8 diagnostic"); - dcx.emit_warn(FromLlvmDiag { message }); - } - llvm::diagnostic::Unsupported(diagnostic_ref) => { + + llvm::diagnostic::Other(diagnostic_ref) => { let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); - dcx.emit_err(FromLlvmDiag { message }); + match diagnostic_ref.severity() { + llvm::DiagnosticSeverity::Error => { + dcx.emit_err(FromLlvmDiag { message }); + } + llvm::DiagnosticSeverity::Warning => { + dcx.emit_warn(FromLlvmDiag { message }); + } + _ => {} + }; } - llvm::diagnostic::UnknownDiagnostic(..) => {} } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 60a29e5c73b16..87e0612bc102d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -6,6 +6,7 @@ use std::{assert_matches, iter, ptr}; use libc::{c_longlong, c_uint}; use rustc_abi::{Align, Endian, Layout, NumScalableVectors, Size}; +use rustc_ast::{IntTy, UintTy}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; use rustc_hir::def::{CtorKind, DefKind}; @@ -794,9 +795,50 @@ fn build_basic_type_di_node<'ll, 'tcx>( _ => bug!("debuginfo::build_basic_type_di_node - `t` is invalid type"), }; - let ty_di_node = create_basic_type(cx, name, cx.size_of(t), encoding); + // Around LLDB 21 or 22, LLDB started using prebuilt Clang type nodes for primitives rather than + // reading the full DWARF data. These nodes are based on the size and signedness of the + // primitive, and ignore pretty much all other fields. This causes 2 issues: + // 1. type names get normalized to C-style names which isn't ideal. The normalization occurs + // even in generic args. + // 2. if you have a generic type `S`, and 2 instantiations are `S` + // and `S` (on a 64-bit target), the use of prebuilt nodes causes a name collision. + // Whichever instantiation is interacted with first will work fine, all others will break a + // bunch of stuff in the LLDB pipeline. To avoid this, we explicitly treat `usize` and `isize` + // as typedefs of their equivalent types. For more info see: llvm/llvm-project#196812 + + let mut needs_typedef = cpp_like_debuginfo; + + let ty_di_node = match t.kind() { + ty::Uint(UintTy::Usize) => { + needs_typedef = true; + + let equivalent = match t.primitive_size(cx.tcx).bits() { + 8 => cx.tcx.types.u8, + 16 => cx.tcx.types.u16, + 32 => cx.tcx.types.u32, + 64 => cx.tcx.types.u64, + 128 => cx.tcx.types.u128, + x => bug!("Unexpected signed int size {x}"), + }; + type_di_node(cx, equivalent) + } + ty::Int(IntTy::Isize) => { + needs_typedef = true; + + let equivalent = match t.primitive_size(cx.tcx).bits() { + 8 => cx.tcx.types.i8, + 16 => cx.tcx.types.i16, + 32 => cx.tcx.types.i32, + 64 => cx.tcx.types.i64, + 128 => cx.tcx.types.i128, + x => bug!("Unexpected signed int size: {x}"), + }; + type_di_node(cx, equivalent) + } + _ => create_basic_type(cx, name, cx.size_of(t), encoding), + }; - if !cpp_like_debuginfo { + if !needs_typedef { return DINodeCreationResult::new(ty_di_node, false); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 59b2cd329ae76..74cac217837d7 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -75,7 +75,6 @@ impl<'ll> OptimizationDiagnostic<'ll> { } pub(crate) struct SrcMgrDiagnostic { - pub level: super::DiagnosticLevel, pub message: String, pub source: Option<(String, Vec)>, } @@ -86,7 +85,6 @@ impl SrcMgrDiagnostic { // diagnostics. let mut have_source = false; let mut buffer = String::new(); - let mut level = super::DiagnosticLevel::Error; let mut loc = 0; let mut ranges = [0; 8]; let mut num_ranges = ranges.len() / 2; @@ -96,7 +94,6 @@ impl SrcMgrDiagnostic { diag, message, buffer, - &mut level, &mut loc, ranges.as_mut_ptr(), &mut num_ranges, @@ -108,7 +105,6 @@ impl SrcMgrDiagnostic { SrcMgrDiagnostic { message, - level, source: have_source.then(|| { let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)]; for i in 0..num_ranges { @@ -122,7 +118,7 @@ impl SrcMgrDiagnostic { #[derive(Clone)] pub(crate) struct InlineAsmDiagnostic { - pub level: super::DiagnosticLevel, + pub severity: super::DiagnosticSeverity, pub cookie: u64, pub message: String, pub source: Option<(String, Vec)>, @@ -132,14 +128,13 @@ impl InlineAsmDiagnostic { unsafe fn unpackInlineAsm(di: &DiagnosticInfo) -> Self { let mut cookie = 0; let mut message = None; - let mut level = super::DiagnosticLevel::Error; unsafe { - super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); + super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut cookie, &mut message); } InlineAsmDiagnostic { - level, + severity: di.severity(), cookie, message: super::twine_to_string(message.unwrap()), source: None, @@ -151,7 +146,7 @@ impl InlineAsmDiagnostic { let smdiag = unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) }; InlineAsmDiagnostic { - level: smdiag.level, + severity: di.severity(), cookie, message: smdiag.message, source: smdiag.source, @@ -162,13 +157,9 @@ impl InlineAsmDiagnostic { pub(crate) enum Diagnostic<'ll> { Optimization(OptimizationDiagnostic<'ll>), InlineAsm(InlineAsmDiagnostic), - PGO(&'ll DiagnosticInfo), - Linker(&'ll DiagnosticInfo), - Unsupported(&'ll DiagnosticInfo), - /// LLVM has other types that we do not wrap here. - #[expect(dead_code)] - UnknownDiagnostic(&'ll DiagnosticInfo), + /// LLVM has other types that we do not distinguish here. + Other(&'ll DiagnosticInfo), } impl<'ll> Diagnostic<'ll> { @@ -206,14 +197,16 @@ impl<'ll> Diagnostic<'ll> { Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) } - Dk::PGOProfile => PGO(di), - Dk::Linker => Linker(di), - Dk::Unsupported => Unsupported(di), - Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), - _ => UnknownDiagnostic(di), + _ => Other(di), } } } } + +impl DiagnosticInfo { + pub(crate) fn severity(&self) -> super::DiagnosticSeverity { + unsafe { super::LLVMGetDiagInfoSeverity(self) } + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a8ededf305a29..cc9be9a0d5093 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -551,15 +551,15 @@ pub(crate) enum DiagnosticKind { SrcMgr, } -/// LLVMRustDiagnosticLevel +/// LLVMDiagnosticSeverity #[derive(Copy, Clone)] #[repr(C)] #[allow(dead_code)] // Variants constructed by C++. -pub(crate) enum DiagnosticLevel { +pub(crate) enum DiagnosticSeverity { Error, Warning, - Note, Remark, + Note, } unsafe extern "C" { @@ -2502,13 +2502,13 @@ unsafe extern "C" { pub(crate) fn LLVMRustUnpackInlineAsmDiagnostic<'a>( DI: &'a DiagnosticInfo, - level_out: &mut DiagnosticLevel, cookie_out: &mut u64, message_out: &mut Option<&'a Twine>, ); pub(crate) fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString); pub(crate) fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind; + pub(crate) fn LLVMGetDiagInfoSeverity(DI: &DiagnosticInfo) -> DiagnosticSeverity; pub(crate) fn LLVMRustGetSMDiagnostic<'a>( DI: &'a DiagnosticInfo, @@ -2519,7 +2519,6 @@ unsafe extern "C" { d: &SMDiagnostic, message_out: &RustString, buffer_out: &RustString, - level_out: &mut DiagnosticLevel, loc_out: &mut c_uint, ranges_out: *mut c_uint, num_ranges: &mut usize, diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index 5167737ac001f..6273414e9ccda 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -2299,19 +2299,21 @@ pub(crate) enum InvalidNanComparisons { #[derive(Subdiagnostic)] pub(crate) enum InvalidNanComparisonsSuggestion { #[multipart_suggestion( - "use `f32::is_nan()` or `f64::is_nan()` instead", + "use the `is_nan` method instead", style = "verbose", applicability = "machine-applicable" )] - Spanful { - #[suggestion_part(code = "!")] - neg: Option, - #[suggestion_part(code = ".is_nan()")] - float: Span, + Ufcs { + prefix: String, + #[suggestion_part(code = "{prefix}")] + prefix_span: Span, + suffix: &'static str, + #[suggestion_part(code = "{suffix}")] + close_span: Span, #[suggestion_part(code = "")] - nan_plus_binop: Span, + remove_nan: Span, }, - #[help("use `f32::is_nan()` or `f64::is_nan()` instead")] + #[help("use the `is_nan` method instead")] Spanless, } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 87b79f12838ae..08c0e8d6f2557 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -2,6 +2,7 @@ use std::iter; use rustc_abi::{BackendRepr, TagEncoding, Variants, WrappingRange}; use rustc_ast as ast; +use rustc_ast::util::parser::ExprPrecedence; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; use rustc_hir as hir; @@ -112,8 +113,8 @@ declare_lint! { } declare_lint! { - /// The `invalid_nan_comparisons` lint checks comparison with `f32::NAN` or `f64::NAN` - /// as one of the operand. + /// The `invalid_nan_comparisons` lint checks comparisons with the `NAN` constants + /// of `f16`, `f32`, `f64`, and `f128`. /// /// ### Example /// @@ -126,8 +127,8 @@ declare_lint! { /// /// ### Explanation /// - /// NaN does not compare meaningfully to anything – not - /// even itself – so those comparisons are always false. + /// NaN compares unequal to every floating-point value, including itself. + /// Use the `is_nan` method to check whether a value is NaN. INVALID_NAN_COMPARISONS, Warn, "detects invalid floating point NaN comparisons" @@ -228,59 +229,124 @@ fn lint_nan<'tcx>( l: &'tcx hir::Expr<'tcx>, r: &'tcx hir::Expr<'tcx>, ) { - fn is_nan(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let expr = expr.peel_blocks().peel_borrows(); - match expr.kind { - ExprKind::Path(qpath) => { - let Some(def_id) = cx.typeck_results().qpath_res(&qpath, expr.hir_id).opt_def_id() - else { - return false; - }; + fn nan_ty(cx: &LateContext<'_>, mut expr: &hir::Expr<'_>) -> Option { + loop { + expr = expr.peel_blocks(); + match expr.kind { + ExprKind::AddrOf(.., inner) => expr = inner, + _ => break, + } + } + let ExprKind::Path(qpath) = expr.kind else { return None }; + let def_id = cx.typeck_results().qpath_res(&qpath, expr.hir_id).opt_def_id()?; + Some(match cx.tcx.get_diagnostic_name(def_id)? { + sym::f16_nan => ty::FloatTy::F16, + sym::f32_nan => ty::FloatTy::F32, + sym::f64_nan => ty::FloatTy::F64, + sym::f128_nan => ty::FloatTy::F128, + _ => return None, + }) + } - matches!( - cx.tcx.get_diagnostic_name(def_id), - Some(sym::f16_nan | sym::f32_nan | sym::f64_nan | sym::f128_nan) - ) + fn nan_method_path( + cx: &LateContext<'_>, + mut nan: &hir::Expr<'_>, + float_ty: ty::FloatTy, + cmp_span: Span, + ) -> Option { + loop { + match nan.kind { + ExprKind::AddrOf(.., inner) => nan = inner, + ExprKind::Block(block, _) if block.stmts.is_empty() => nan = block.expr?, + _ => break, } - _ => false, + } + let ExprKind::Path(hir::QPath::TypeRelative(ty, _)) = nan.kind else { + return None; + }; + if !ty.span.from_expansion() && cmp_span.contains(ty.span) { + let ty = cx.sess().source_map().span_to_snippet(ty.span).ok()?; + Some(format!("<{ty}>::is_nan")) + } else if matches!(float_ty, ty::FloatTy::F32 | ty::FloatTy::F64) { + let krate = std_or_core(cx)?; + Some(format!("::{krate}::primitive::{}::is_nan", float_ty.name_str())) + } else { + None } } - fn eq_ne( - e: &hir::Expr<'_>, - l: &hir::Expr<'_>, - r: &hir::Expr<'_>, - f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion, - ) -> InvalidNanComparisons { - let suggestion = if let Some(l_span) = l.span.find_ancestor_inside(e.span) - && let Some(r_span) = r.span.find_ancestor_inside(e.span) - { - f(l_span, r_span) + fn eq_ne_suggestion<'a>( + cx: &LateContext<'a>, + cmp: &'a hir::Expr<'a>, + value: &'a hir::Expr<'a>, + nan: &'a hir::Expr<'a>, + float_ty: ty::FloatTy, + is_ne: bool, + ) -> InvalidNanComparisonsSuggestion { + if cmp.span.from_expansion() { + return InvalidNanComparisonsSuggestion::Spanless; + } + let (Some(value_span), Some(nan_span)) = ( + value.span.find_ancestor_inside_same_ctxt(cmp.span), + nan.span.find_ancestor_inside_same_ctxt(cmp.span), + ) else { + return InvalidNanComparisonsSuggestion::Spanless; + }; + if value_span.overlaps(nan_span) { + return InvalidNanComparisonsSuggestion::Spanless; + } + let remove_nan = if nan_span.lo() < value_span.lo() { + nan_span.until(value_span) } else { - InvalidNanComparisonsSuggestion::Spanless + value_span.shrink_to_hi().to(nan_span) }; - InvalidNanComparisons::EqNe { suggestion } + let Some(mut ty) = cx.typeck_results().expr_ty_opt(value) else { + return InvalidNanComparisonsSuggestion::Spanless; + }; + let mut deref_count = 0; + while let ty::Ref(_, inner, _) = *ty.kind() { + deref_count += 1; + ty = inner; + } + let neg = if is_ne { "!" } else { "" }; + let Some(method_path) = nan_method_path(cx, nan, float_ty, cmp.span) else { + return InvalidNanComparisonsSuggestion::Spanless; + }; + let (open, suffix) = if deref_count != 0 && cx.precedence(value) < ExprPrecedence::Prefix { + ("(", "))") + } else { + ("", ")") + }; + InvalidNanComparisonsSuggestion::Ufcs { + prefix: format!("{neg}{method_path}({}{open}", "*".repeat(deref_count)), + prefix_span: value_span.shrink_to_lo(), + suffix, + close_span: value_span.shrink_to_hi(), + remove_nan, + } } + let Some((value, nan, float_ty)) = nan_ty(cx, l) + .map(|float_ty| (r, l, float_ty)) + .or_else(|| nan_ty(cx, r).map(|float_ty| (l, r, float_ty))) + else { + return; + }; + let typeck_results = cx.typeck_results(); + // Custom comparison implementations need not follow primitive float NaN semantics. + if ![l, r].into_iter().all(|operand| { + typeck_results + .expr_ty_opt(operand) + .is_some_and(|ty| matches!(*ty.peel_refs().kind(), ty::Float(fty) if fty == float_ty)) + }) { + return; + } let lint = match binop { - hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => { - eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { - nan_plus_binop: l_span.until(r_span), - float: r_span.shrink_to_hi(), - neg: (binop == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()), - }) - } - hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => { - eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { - nan_plus_binop: l_span.shrink_to_hi().to(r_span), - float: l_span.shrink_to_hi(), - neg: (binop == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()), - }) - } - hir::BinOpKind::Lt | hir::BinOpKind::Le | hir::BinOpKind::Gt | hir::BinOpKind::Ge - if is_nan(cx, l) || is_nan(cx, r) => - { + hir::BinOpKind::Eq | hir::BinOpKind::Ne => InvalidNanComparisons::EqNe { + suggestion: eq_ne_suggestion(cx, e, value, nan, float_ty, binop == hir::BinOpKind::Ne), + }, + hir::BinOpKind::Lt | hir::BinOpKind::Le | hir::BinOpKind::Gt | hir::BinOpKind::Ge => { InvalidNanComparisons::LtLeGtGe } _ => return, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f379799ecde9e..1edc547023b9c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1217,32 +1217,15 @@ enum class LLVMRustDiagnosticLevel { Remark, }; -extern "C" void LLVMRustUnpackInlineAsmDiagnostic( - LLVMDiagnosticInfoRef DI, LLVMRustDiagnosticLevel *LevelOut, - uint64_t *CookieOut, const Twine **MessageOut) { +extern "C" void LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, + uint64_t *CookieOut, + const Twine **MessageOut) { // Undefined to call this not on an inline assembly diagnostic! llvm::DiagnosticInfoInlineAsm *IA = static_cast(unwrap(DI)); *CookieOut = IA->getLocCookie(); *MessageOut = &IA->getMsgStr(); - - switch (IA->getSeverity()) { - case DS_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case DS_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case DS_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case DS_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); - } } extern "C" void LLVMRustWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef DI, @@ -1324,30 +1307,12 @@ extern "C" const SMDiagnostic *LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI, extern "C" bool LLVMRustUnpackSMDiagnostic(const SMDiagnostic *DRef, RustStringRef MessageOut, - RustStringRef BufferOut, - LLVMRustDiagnosticLevel *LevelOut, unsigned *LocOut, + RustStringRef BufferOut, unsigned *LocOut, unsigned *RangesOut, size_t *NumRanges) { const SMDiagnostic &D = *DRef; auto MessageOS = RawRustStringOstream(MessageOut); MessageOS << D.getMessage(); - switch (D.getKind()) { - case SourceMgr::DK_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case SourceMgr::DK_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case SourceMgr::DK_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case SourceMgr::DK_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); - } - if (D.getLoc() == SMLoc()) return false; diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index f7a6beb2b8c63..600e897b13bbd 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -135,6 +135,14 @@ where #[inline] #[rustc_inherit_overflow_checks] fn advance_by(&mut self, mut n: usize) -> Result<(), NonZero> { + if self.n > 0 && n == 0 { + // If we try to process our skips now, we might witness the end of the inner iterator, + // but there's no valid `Err(k)` that we could return. This is especially a problem for + // unfused iterators that might end up called again by `Chain`, for example, so it's + // better that we do nothing at all. + return Ok(()); + } + let skip_inner = self.n; let skip_and_advance = skip_inner.saturating_add(n); diff --git a/library/core/src/num/imp/int_bits.rs b/library/core/src/num/imp/int_bits.rs index 2bc95e66e7ef6..dbb1a54fc59f6 100644 --- a/library/core/src/num/imp/int_bits.rs +++ b/library/core/src/num/imp/int_bits.rs @@ -115,7 +115,7 @@ macro_rules! uint_impl { // [0; n], [X; a], [0; n], [0; b] // q // [0; n], [0; a + n], [Y; b] // x ^= q // [0; n + n], [X; a], [0; b] // q >> n - // [0; n], [0; n], [X; a], [Y; b] // x ^= q << n + // [0; n], [0; n], [X; a], [Y; b] // x ^= q >> n // ``` // Only zeros are shifted out, satisfying the assumption // for the next group. @@ -123,9 +123,18 @@ macro_rules! uint_impl { // In effect, the upper run of data is swapped with the // group of `n` zeros below it. let q = x & masks[stage]; - x ^= q; - x ^= q >> n; + if cfg!(all(target_arch = "aarch64", target_feature = "neon")) && $U::BITS <= 64 + { + // `q >> n` has no set bits in common with `x ^ q`, so addition + // is equivalent to XOR here. For widths up to 64 bits this + // allows AArch64 to use `usra`. For `u128`, this add may introduce + // a slower cross-limb carry chain. + x = (x & !masks[stage]).wrapping_add(q >> n); + } else { + x ^= q; + x ^= q >> n; + } stage += 1; } x diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index 7c008531c1f5a..5b80b4edc20de 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -1,4 +1,5 @@ -/// The unary logical negation operator `!`. +/// The unary negation operator `!`. It performs either logical or bitwise negation, +/// depending on the type. /// /// # Examples /// @@ -37,15 +38,23 @@ pub const trait Not { #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// Performs the unary `!` operation. + /// Performs the unary `!` operation using logical or bitwise negation. /// /// # Examples /// /// ``` + /// // Logical negation changes between true and false: /// assert_eq!(!true, false); /// assert_eq!(!false, true); + /// + /// // Bitwise negation changes between 0 and 1 in the binary + /// // representation of integers: /// assert_eq!(!1u8, 254); /// assert_eq!(!0u8, 255); + /// + /// // The same examples, represented in binary: + /// assert_eq!(!0b0000_0001u8, 0b1111_1110); + /// assert_eq!(!0b0000_0000u8, 0b1111_1111); /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/coretests/tests/iter/adapters/skip.rs b/library/coretests/tests/iter/adapters/skip.rs index 8d5d06ad9fb3a..cfd00ac609715 100644 --- a/library/coretests/tests/iter/adapters/skip.rs +++ b/library/coretests/tests/iter/adapters/skip.rs @@ -86,6 +86,31 @@ fn test_skip_advance_by() { assert_eq!((0..0).skip(1).advance_back_by(0), Ok(())); } +#[test] +fn test_skip_unfused_advance_by() { + /// A legal non-fused iterator: `None` once, then `Some(1)`, `Some(2)`, ... + struct Gap(u32); + + impl Iterator for Gap { + type Item = u32; + fn next(&mut self) -> Option { + self.0 += 1; + if self.0 == 1 { None } else { Some(self.0 - 1) } + } + } + + assert_eq!(Gap(0).skip(1).next(), None); + + let mut iter = Gap(0).skip(1); + assert_eq!(iter.advance_by(0), Ok(())); + // `Ok` means we didn't see the (unfused) end yet... + assert_eq!(iter.next(), None); + + // Chain also depends on this behavior internally + assert_eq!(Gap(0).skip(1).chain(empty()).next(), None); + assert_eq!(Gap(0).skip(1).chain(empty()).nth(0), None); +} + #[test] fn test_iterator_skip_count() { let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; diff --git a/tests/codegen-llvm/debug-vtable.rs b/tests/codegen-llvm/debug-vtable.rs index 8a7b1cc3c4bcc..031153832629c 100644 --- a/tests/codegen-llvm/debug-vtable.rs +++ b/tests/codegen-llvm/debug-vtable.rs @@ -19,7 +19,7 @@ // CHECK: @vtable.3 = private constant <{ // CHECK: @vtable.4 = private constant <{ -// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize" +// NONMSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" // MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" // NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()" // MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >" diff --git a/tests/debuginfo/basic-types/lldb_input/non_windows.json b/tests/debuginfo/basic-types/lldb_input/non_windows.json index af225246e6109..67c45674981a2 100644 --- a/tests/debuginfo/basic-types/lldb_input/non_windows.json +++ b/tests/debuginfo/basic-types/lldb_input/non_windows.json @@ -12,7 +12,7 @@ "value": false }, "i": { - "type": "long", + "type": "isize", "pretty_print": "-1", "value": -1 }, @@ -43,7 +43,7 @@ "value": -64 }, "u": { - "type": "unsigned long", + "type": "usize", "pretty_print": "1", "value": 1 }, diff --git a/tests/debuginfo/basic-types/lldb_input/windows_gnu.json b/tests/debuginfo/basic-types/lldb_input/windows_gnu.json index 80c35ffcbea60..06b21d7cb0b35 100644 --- a/tests/debuginfo/basic-types/lldb_input/windows_gnu.json +++ b/tests/debuginfo/basic-types/lldb_input/windows_gnu.json @@ -1,7 +1,7 @@ { "bless_metadata": { "python_version": "3.11.9 (tags/v3.11.9:de54cf5, Apr 2 2024, 10:12:12) [MSC v.1938 64 bit (AMD64)]", - "debugger_version": "lldb version 22.1.2 (https://github.com/llvm/llvm-project revision 1ab49a973e210e97d61e5db6557180dcb92c3e98)\n clang revision 1ab49a973e210e97d61e5db6557180dcb92c3e98\n llvm revision 1ab49a973e210e97d61e5db6557180dcb92c3e98", + "debugger_version": "lldb version 22.1.8 (https://github.com/llvm/llvm-project revision ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)\n clang revision ca7933e47d3a3451d81e72ac174dcb5aa28b59d1\n llvm revision ca7933e47d3a3451d81e72ac174dcb5aa28b59d1", "feature_flags": "LLDBFeature.StaticFields|TypeRecognizers|Float128" }, "breakpoints": [ @@ -12,7 +12,7 @@ "value": false }, "i": { - "type": "long long", + "type": "isize", "pretty_print": "-1", "value": -1 }, @@ -43,7 +43,7 @@ "value": -64 }, "u": { - "type": "unsigned long long", + "type": "usize", "pretty_print": "1", "value": 1 }, diff --git a/tests/debuginfo/pretty-std/lldb_input/non_windows.json b/tests/debuginfo/pretty-std/lldb_input/non_windows.json index 737eb5004b2bf..f76ba1ded06a1 100644 --- a/tests/debuginfo/pretty-std/lldb_input/non_windows.json +++ b/tests/debuginfo/pretty-std/lldb_input/non_windows.json @@ -162,7 +162,7 @@ }, { "name": "length", - "type": "unsigned long", + "type": "usize", "offset": 8 } ] @@ -178,7 +178,7 @@ }, { "name": "length", - "type": "unsigned long", + "type": "usize", "offset": 8 } ] @@ -273,7 +273,7 @@ }, { "name": "len", - "type": "unsigned long", + "type": "usize", "offset": 16 } ], @@ -293,7 +293,7 @@ }, { "name": "len", - "type": "unsigned long", + "type": "usize", "offset": 16 } ], @@ -322,7 +322,7 @@ "fields": [ { "name": "__0", - "type": "unsigned long", + "type": "usize", "offset": 0 } ] @@ -560,6 +560,11 @@ "size": 2, "type_class": 4, "basic_type": 12 + }, + "usize": { + "size": 8, + "type_class": 32768, + "basic_type": 16 } } } diff --git a/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json b/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json index 7f7772bd4caa1..56bfb83deef32 100644 --- a/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json +++ b/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json @@ -173,7 +173,7 @@ }, { "name": "length", - "type": "unsigned long long", + "type": "usize", "offset": 8 } ] @@ -284,7 +284,7 @@ }, { "name": "len", - "type": "unsigned long long", + "type": "usize", "offset": 16 } ], diff --git a/tests/debuginfo/rc_arc.rs b/tests/debuginfo/rc_arc.rs index adeb96dba1b80..e1af1eba02193 100644 --- a/tests/debuginfo/rc_arc.rs +++ b/tests/debuginfo/rc_arc.rs @@ -21,6 +21,11 @@ //@ lldb-check:[...] strong=11, weak=2 { value = 111 } //@ lldb-command:v arc //@ lldb-check:[...] strong=21, weak=2 { data = 222 } +//@ lldb-command:continue +//@ lldb-command:v rc_u64 +//@ lldb-check:[...] rc_u64 = strong=1, weak=1 { value = 10 } +//@ lldb-command:v rc_usize +//@ lldb-check:[...] rc_usize = strong=1, weak=1 { value = 20 } // === CDB TESTS ================================================================================== @@ -132,6 +137,11 @@ fn main() { let slice_arc_weak = Arc::downgrade(&slice_arc); zzz(); // #break + + let rc_u64 = Rc::new(10u64); + let rc_usize = Rc::new(20usize); + + zzz(); // #break } fn inc_ref_count(rc: &T, count: usize) { diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed deleted file mode 100644 index 2d88c274080b6..0000000000000 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed +++ /dev/null @@ -1,50 +0,0 @@ -//@ check-pass -//@ run-rustfix - -#![feature(f16, f128)] - -fn main() { - let x = 5f16; - let _ = x.is_nan(); - //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); - //~^ WARN incorrect NaN comparison - - let x = 5f32; - let _ = x.is_nan(); - //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); - //~^ WARN incorrect NaN comparison - - let x = 5f64; - let _ = x.is_nan(); - //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); - //~^ WARN incorrect NaN comparison - - let x = 5f128; - let _ = x.is_nan(); - //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); - //~^ WARN incorrect NaN comparison - - let b = &2.3f32; - if !b.is_nan() {} - //~^ WARN incorrect NaN comparison - - let b = &2.3f32; - if !b.is_nan() {} - //~^ WARN incorrect NaN comparison - - let _ = - !b.is_nan(); - - #[allow(unused_macros)] - macro_rules! nan { () => { f32::NAN }; } - macro_rules! number { () => { 5f32 }; } - - let _ = number!().is_nan(); - //~^ WARN incorrect NaN comparison - let _ = !number!().is_nan(); - //~^ WARN incorrect NaN comparison -} diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.rs b/tests/ui/lint/invalid-nan-comparison-suggestion.rs deleted file mode 100644 index 9175344786948..0000000000000 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.rs +++ /dev/null @@ -1,53 +0,0 @@ -//@ check-pass -//@ run-rustfix - -#![feature(f16, f128)] - -fn main() { - let x = 5f16; - let _ = x == f16::NAN; - //~^ WARN incorrect NaN comparison - let _ = x != f16::NAN; - //~^ WARN incorrect NaN comparison - - let x = 5f32; - let _ = x == f32::NAN; - //~^ WARN incorrect NaN comparison - let _ = x != f32::NAN; - //~^ WARN incorrect NaN comparison - - let x = 5f64; - let _ = x == f64::NAN; - //~^ WARN incorrect NaN comparison - let _ = x != f64::NAN; - //~^ WARN incorrect NaN comparison - - let x = 5f128; - let _ = x == f128::NAN; - //~^ WARN incorrect NaN comparison - let _ = x != f128::NAN; - //~^ WARN incorrect NaN comparison - - let b = &2.3f32; - if b != &f32::NAN {} - //~^ WARN incorrect NaN comparison - - let b = &2.3f32; - if b != { &f32::NAN } {} - //~^ WARN incorrect NaN comparison - - let _ = - b != { - //~^ WARN incorrect NaN comparison - &f32::NAN - }; - - #[allow(unused_macros)] - macro_rules! nan { () => { f32::NAN }; } - macro_rules! number { () => { 5f32 }; } - - let _ = nan!() == number!(); - //~^ WARN incorrect NaN comparison - let _ = number!() != nan!(); - //~^ WARN incorrect NaN comparison -} diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr deleted file mode 100644 index f9b1428de464c..0000000000000 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr +++ /dev/null @@ -1,165 +0,0 @@ -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:8:13 - | -LL | let _ = x == f16::NAN; - | ^^^^^^^^^^^^^ - | - = note: `#[warn(invalid_nan_comparisons)]` on by default -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x == f16::NAN; -LL + let _ = x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:10:13 - | -LL | let _ = x != f16::NAN; - | ^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x != f16::NAN; -LL + let _ = !x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:14:13 - | -LL | let _ = x == f32::NAN; - | ^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x == f32::NAN; -LL + let _ = x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:16:13 - | -LL | let _ = x != f32::NAN; - | ^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x != f32::NAN; -LL + let _ = !x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:20:13 - | -LL | let _ = x == f64::NAN; - | ^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x == f64::NAN; -LL + let _ = x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:22:13 - | -LL | let _ = x != f64::NAN; - | ^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x != f64::NAN; -LL + let _ = !x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:26:13 - | -LL | let _ = x == f128::NAN; - | ^^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x == f128::NAN; -LL + let _ = x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:28:13 - | -LL | let _ = x != f128::NAN; - | ^^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = x != f128::NAN; -LL + let _ = !x.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:32:8 - | -LL | if b != &f32::NAN {} - | ^^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - if b != &f32::NAN {} -LL + if !b.is_nan() {} - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:36:8 - | -LL | if b != { &f32::NAN } {} - | ^^^^^^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - if b != { &f32::NAN } {} -LL + if !b.is_nan() {} - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:40:9 - | -LL | / b != { -LL | | -LL | | &f32::NAN -LL | | }; - | |_________^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - b != { -LL - -LL - &f32::NAN -LL - }; -LL + !b.is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:49:13 - | -LL | let _ = nan!() == number!(); - | ^^^^^^^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = nan!() == number!(); -LL + let _ = number!().is_nan(); - | - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:51:13 - | -LL | let _ = number!() != nan!(); - | ^^^^^^^^^^^^^^^^^^^ - | -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - let _ = number!() != nan!(); -LL + let _ = !number!().is_nan(); - | - -warning: 13 warnings emitted - diff --git a/tests/ui/lint/invalid-nan-comparison.rs b/tests/ui/lint/invalid-nan-comparisons/basic.rs similarity index 100% rename from tests/ui/lint/invalid-nan-comparison.rs rename to tests/ui/lint/invalid-nan-comparisons/basic.rs diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparisons/basic.stderr similarity index 64% rename from tests/ui/lint/invalid-nan-comparison.stderr rename to tests/ui/lint/invalid-nan-comparisons/basic.stderr index 486d2a9636c95..77cd6fc111e75 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparisons/basic.stderr @@ -1,302 +1,302 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:12:20 + --> $DIR/basic.rs:12:20 | LL | const TEST: bool = 5f32 == f32::NAN; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(invalid_nan_comparisons)]` on by default -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - const TEST: bool = 5f32 == f32::NAN; -LL + const TEST: bool = 5f32.is_nan(); +LL + const TEST: bool = ::is_nan(5f32); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:18:5 + --> $DIR/basic.rs:18:5 | LL | x == f16::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f16::NAN; -LL + x.is_nan(); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:20:5 + --> $DIR/basic.rs:20:5 | LL | x != f16::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f16::NAN; -LL + !x.is_nan(); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:22:5 + --> $DIR/basic.rs:22:5 | LL | x < f16::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:24:5 + --> $DIR/basic.rs:24:5 | LL | x > f16::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:26:5 + --> $DIR/basic.rs:26:5 | LL | x <= f16::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:28:5 + --> $DIR/basic.rs:28:5 | LL | x >= f16::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:30:5 + --> $DIR/basic.rs:30:5 | LL | number!() == f16::NAN; | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f16::NAN; -LL + number!().is_nan(); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:32:5 + --> $DIR/basic.rs:32:5 | LL | f16::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f16::NAN != number!(); -LL + !number!().is_nan(); +LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:39:5 + --> $DIR/basic.rs:39:5 | LL | x == f32::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f32::NAN; -LL + x.is_nan(); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:41:5 + --> $DIR/basic.rs:41:5 | LL | x != f32::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f32::NAN; -LL + !x.is_nan(); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:43:5 + --> $DIR/basic.rs:43:5 | LL | x < f32::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:45:5 + --> $DIR/basic.rs:45:5 | LL | x > f32::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:47:5 + --> $DIR/basic.rs:47:5 | LL | x <= f32::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:49:5 + --> $DIR/basic.rs:49:5 | LL | x >= f32::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:51:5 + --> $DIR/basic.rs:51:5 | LL | number!() == f32::NAN; | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f32::NAN; -LL + number!().is_nan(); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:53:5 + --> $DIR/basic.rs:53:5 | LL | f32::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f32::NAN != number!(); -LL + !number!().is_nan(); +LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:60:5 + --> $DIR/basic.rs:60:5 | LL | x == f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f64::NAN; -LL + x.is_nan(); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:62:5 + --> $DIR/basic.rs:62:5 | LL | x != f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f64::NAN; -LL + !x.is_nan(); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:64:5 + --> $DIR/basic.rs:64:5 | LL | x < f64::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:66:5 + --> $DIR/basic.rs:66:5 | LL | x > f64::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:68:5 + --> $DIR/basic.rs:68:5 | LL | x <= f64::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:70:5 + --> $DIR/basic.rs:70:5 | LL | x >= f64::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:72:5 + --> $DIR/basic.rs:72:5 | LL | number!() == f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f64::NAN; -LL + number!().is_nan(); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:74:5 + --> $DIR/basic.rs:74:5 | LL | f64::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f64::NAN != number!(); -LL + !number!().is_nan(); +LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:81:5 + --> $DIR/basic.rs:81:5 | LL | x == f128::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f128::NAN; -LL + x.is_nan(); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:83:5 + --> $DIR/basic.rs:83:5 | LL | x != f128::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f128::NAN; -LL + !x.is_nan(); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:85:5 + --> $DIR/basic.rs:85:5 | LL | x < f128::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:87:5 + --> $DIR/basic.rs:87:5 | LL | x > f128::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:89:5 + --> $DIR/basic.rs:89:5 | LL | x <= f128::NAN; | ^^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:91:5 + --> $DIR/basic.rs:91:5 | LL | x >= f128::NAN; | ^^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:93:5 + --> $DIR/basic.rs:93:5 | LL | number!() == f128::NAN; | ^^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f128::NAN; -LL + number!().is_nan(); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:95:5 + --> $DIR/basic.rs:95:5 | LL | f128::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f128::NAN != number!(); -LL + !number!().is_nan(); +LL + !::is_nan(number!()); | warning: 33 warnings emitted diff --git a/tests/ui/lint/invalid-nan-comparisons/custom-comparisons.rs b/tests/ui/lint/invalid-nan-comparisons/custom-comparisons.rs new file mode 100644 index 0000000000000..ccdb7e0d31859 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/custom-comparisons.rs @@ -0,0 +1,73 @@ +//@ check-pass + +#![deny(invalid_nan_comparisons)] + +use std::cmp::Ordering; + +struct NotFloat; + +impl PartialEq for NotFloat { + fn eq(&self, other: &f64) -> bool { + other.is_nan() + } +} + +impl PartialEq for f64 { + fn eq(&self, other: &NotFloat) -> bool { + other == self + } +} + +impl PartialOrd for NotFloat { + fn partial_cmp(&self, other: &f64) -> Option { + other.is_nan().then_some(Ordering::Equal) + } +} + +impl PartialOrd for f64 { + fn partial_cmp(&self, other: &NotFloat) -> Option { + other.partial_cmp(self).map(Ordering::reverse) + } +} + +fn main() { + let value = NotFloat; + let _ = value == f64::NAN; + let _ = value != f64::NAN; + let _ = value < f64::NAN; + let _ = value <= f64::NAN; + let _ = value > f64::NAN; + let _ = value >= f64::NAN; + + let _ = f64::NAN == value; + let _ = f64::NAN != value; + let _ = f64::NAN < value; + let _ = f64::NAN <= value; + let _ = f64::NAN > value; + let _ = f64::NAN >= value; + + let _ = &value == &f64::NAN; + let _ = &value != &f64::NAN; + let _ = &value < &f64::NAN; + let _ = &value <= &f64::NAN; + let _ = &value > &f64::NAN; + let _ = &value >= &f64::NAN; + + let _ = &f64::NAN == &value; + let _ = &f64::NAN != &value; + let _ = &f64::NAN < &value; + let _ = &f64::NAN <= &value; + let _ = &f64::NAN > &value; + let _ = &f64::NAN >= &value; + + generic(value); +} + +fn generic>(value: T) { + let _ = value == f64::NAN; + let _ = value != f64::NAN; + let _ = value < f64::NAN; + let _ = value <= f64::NAN; + let _ = value > f64::NAN; + let _ = value >= f64::NAN; +} diff --git a/tests/ui/lint/invalid-nan-comparisons/no-std.fixed b/tests/ui/lint/invalid-nan-comparisons/no-std.fixed new file mode 100644 index 0000000000000..3e35d14d223d7 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/no-std.fixed @@ -0,0 +1,18 @@ +//@ check-pass +//@ run-rustfix +//@ compile-flags: --crate-type=lib + +#![no_std] + +pub type MacroFloat = ::core::primitive::f64; + +#[allow(non_camel_case_types)] +pub struct f64; + +pub fn check() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = !::core::primitive::f64::is_nan(*b); + //~^ WARN incorrect NaN comparison +} diff --git a/tests/ui/lint/invalid-nan-comparisons/no-std.rs b/tests/ui/lint/invalid-nan-comparisons/no-std.rs new file mode 100644 index 0000000000000..7ace5b976c890 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/no-std.rs @@ -0,0 +1,18 @@ +//@ check-pass +//@ run-rustfix +//@ compile-flags: --crate-type=lib + +#![no_std] + +pub type MacroFloat = ::core::primitive::f64; + +#[allow(non_camel_case_types)] +pub struct f64; + +pub fn check() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = b != &nan!(); + //~^ WARN incorrect NaN comparison +} diff --git a/tests/ui/lint/invalid-nan-comparisons/no-std.stderr b/tests/ui/lint/invalid-nan-comparisons/no-std.stderr new file mode 100644 index 0000000000000..b10909e157020 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/no-std.stderr @@ -0,0 +1,15 @@ +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/no-std.rs:16:13 + | +LL | let _ = b != &nan!(); + | ^^^^^^^^^^^^ + | + = note: `#[warn(invalid_nan_comparisons)]` on by default +help: use the `is_nan` method instead + | +LL - let _ = b != &nan!(); +LL + let _ = !::core::primitive::f64::is_nan(*b); + | + +warning: 1 warning emitted + diff --git a/tests/ui/lint/invalid-nan-comparisons/no-suggestion.rs b/tests/ui/lint/invalid-nan-comparisons/no-suggestion.rs new file mode 100644 index 0000000000000..afe3cb7cfd259 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/no-suggestion.rs @@ -0,0 +1,28 @@ +//@ check-pass + +#![feature(f16, f128)] + +fn main() { + let mut effects = 0; + let _ = 3.3 == { + effects += 1; + f64::NAN + }; + //~^^^^ WARN incorrect NaN comparison + let _ = effects; + + macro_rules! scoped_nan { () => {{ type Float = f64; Float::NAN }}; } + let _ = 3.3 == scoped_nan!(); + //~^ WARN incorrect NaN comparison + + macro_rules! nan16 { () => { f16::NAN }; } + let _ = 3.3 == nan16!(); + //~^ WARN incorrect NaN comparison + macro_rules! nan128 { () => { f128::NAN }; } + let _ = 3.3 != nan128!(); + //~^ WARN incorrect NaN comparison + + macro_rules! compare { () => { 3.3 != f64::NAN }; } + //~^ WARN incorrect NaN comparison + let _ = compare!(); +} diff --git a/tests/ui/lint/invalid-nan-comparisons/no-suggestion.stderr b/tests/ui/lint/invalid-nan-comparisons/no-suggestion.stderr new file mode 100644 index 0000000000000..278f4d225aec4 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/no-suggestion.stderr @@ -0,0 +1,50 @@ +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/no-suggestion.rs:7:13 + | +LL | let _ = 3.3 == { + | _____________^ +LL | | effects += 1; +LL | | f64::NAN +LL | | }; + | |_____^ + | + = help: use the `is_nan` method instead + = note: `#[warn(invalid_nan_comparisons)]` on by default + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/no-suggestion.rs:15:13 + | +LL | let _ = 3.3 == scoped_nan!(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/no-suggestion.rs:19:13 + | +LL | let _ = 3.3 == nan16!(); + | ^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/no-suggestion.rs:22:13 + | +LL | let _ = 3.3 != nan128!(); + | ^^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/no-suggestion.rs:25:36 + | +LL | macro_rules! compare { () => { 3.3 != f64::NAN }; } + | ^^^^^^^^^^^^^^^ +LL | +LL | let _ = compare!(); + | ---------- in this macro invocation + | + = help: use the `is_nan` method instead + +warning: 5 warnings emitted + diff --git a/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed b/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed new file mode 100644 index 0000000000000..be5f477e67992 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed @@ -0,0 +1,215 @@ +//@ check-pass +//@ run-rustfix + +#![feature(f16, f128)] + +extern crate core; + +fn main() { + let x = 5f16; + let _ = ::is_nan(x); + //~^ WARN incorrect NaN comparison + let _ = !::is_nan(x); + //~^ WARN incorrect NaN comparison + + let x = 5f32; + let _ = ::is_nan(x); + //~^ WARN incorrect NaN comparison + let _ = !::is_nan(x); + //~^ WARN incorrect NaN comparison + + let x = 5f64; + let _ = ::is_nan(x); + //~^ WARN incorrect NaN comparison + let _ = !::is_nan(x); + //~^ WARN incorrect NaN comparison + + let x = 5f128; + let _ = ::is_nan(x); + //~^ WARN incorrect NaN comparison + let _ = !::is_nan(x); + //~^ WARN incorrect NaN comparison + + let b = &2.3f32; + if !::is_nan(*b) {} + //~^ WARN incorrect NaN comparison + + let b = &2.3f32; + if !::is_nan(*b) {} + //~^ WARN incorrect NaN comparison + + let _ = + !::is_nan(*b); + + // Issue #164143: an unsuffixed float is constrained by the `NAN` operand. + // Suggesting `.is_nan()` drops that constraint and does not compile. + let b = &3.3; + if !::is_nan(*b) {} + //~^ WARN incorrect NaN comparison + + let mut m = &3.3; + if !::is_nan(*m) { + //~^ WARN incorrect NaN comparison + m = &1.0; + } + let _ = m; + + let unary = &(-3.3); + if !::is_nan(*unary) {} + //~^ WARN incorrect NaN comparison + + let block = &{ 3.3 }; + if !::is_nan(*block) {} + //~^ WARN incorrect NaN comparison + + let (tuple,) = (&3.3,); + if !::is_nan(*tuple) {} + //~^ WARN incorrect NaN comparison + + let arithmetic = &(3.3 + 0.0); + if !::is_nan(*arithmetic) {} + //~^ WARN incorrect NaN comparison + + let x = 1.0f64; + if !::is_nan(*&x) {} + //~^ WARN incorrect NaN comparison + let p = &x; + let _ = ::is_nan(*p); + //~^ WARN incorrect NaN comparison + let _ = ::is_nan(-x); + //~^ WARN incorrect NaN comparison + + shadowed::check(); + nested_operands(); + macro_paths(); + method_resolution::check(); + + let _ = ::is_nan(3.3); + //~^ WARN incorrect NaN comparison + + let _ = !::is_nan(*&3.3); + //~^ WARN incorrect NaN comparison + + let suffixed = 3.3f64; + let copied = suffixed; + let _ = !::is_nan(copied); + //~^ WARN incorrect NaN comparison + + let ascribed: f64 = 3.3; + let _ = !::is_nan(ascribed); + //~^ WARN incorrect NaN comparison + + parameter(1.0); + parameter_ref(&1.0); + let _ = |x: f64| !::is_nan(x); //~ WARN incorrect NaN comparison + + #[allow(unused_macros)] + macro_rules! nan { () => { f32::NAN }; } + macro_rules! number { () => { 5f32 }; } + + let _ = ::std::primitive::f32::is_nan(number!()); + //~^ WARN incorrect NaN comparison + let _ = !::std::primitive::f32::is_nan(number!()); + //~^ WARN incorrect NaN comparison +} + +fn parameter(x: f64) { + let _ = ::is_nan(x); + //~^ WARN incorrect NaN comparison +} + +fn parameter_ref(x: &f32) { + if !::is_nan(*x) {} + //~^ WARN incorrect NaN comparison +} + +fn nested_operands() { + let x = 1.0f64; + let _ = ::is_nan(*(&x as &f64)); + //~^ WARN incorrect NaN comparison + let _ = !::is_nan(*{ &{ 3.3 } }); + //~^ WARN incorrect NaN comparison + let _ = ::is_nan(***&&&3.3); + //~^ WARN incorrect NaN comparison + let b = &&&3.3; + let _ = !::is_nan(***b); + //~^ WARN incorrect NaN comparison + let b = &mut 3.3; + let _ = !::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = ::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = !::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &&3.3; + let _ = ::is_nan(**b); + //~^ WARN incorrect NaN comparison + + let b = &(-3.3); + let _ = !::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &(3.3 + 0.0); + let _ = ::is_nan(*b); + //~^ WARN incorrect NaN comparison + + macro_rules! borrowed { () => { &3.3 }; } + let _ = !::is_nan(*borrowed!()); + //~^ WARN incorrect NaN comparison +} + +pub type MacroFloat = f64; + +fn macro_paths() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = !::std::primitive::f64::is_nan(*b); + //~^ WARN incorrect NaN comparison +} + +mod shadowed { + #[allow(dead_code, non_camel_case_types)] + struct f64; + use ::core::primitive::f64 as Float; + + pub fn check() { + let b = &3.3; + if !<::core::primitive::f64>::is_nan(*b) {} + //~^ WARN incorrect NaN comparison + let c = &4.4; + if !::is_nan(*c) {} + //~^ WARN incorrect NaN comparison + let d = &5.5; + if !::is_nan(*d) {} + //~^ WARN incorrect NaN comparison + } +} + +mod method_resolution { + mod f64 { + pub fn is_nan(_: ::core::primitive::f64) {} + } + + trait IsNan { + fn is_nan(self); + } + + impl IsNan for &f64 { + fn is_nan(self) {} + } + + pub fn check() { + let _: () = f64::is_nan(5.0); + let _: () = (&5f64).is_nan(); + + let x = 5f64; + let _: bool = ::is_nan(x); + //~^ WARN incorrect NaN comparison + + let x = &5f64; + let _: bool = ::is_nan(*x); + //~^ WARN incorrect NaN comparison + } +} diff --git a/tests/ui/lint/invalid-nan-comparisons/suggestion.rs b/tests/ui/lint/invalid-nan-comparisons/suggestion.rs new file mode 100644 index 0000000000000..96b7618e921e9 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/suggestion.rs @@ -0,0 +1,218 @@ +//@ check-pass +//@ run-rustfix + +#![feature(f16, f128)] + +extern crate core; + +fn main() { + let x = 5f16; + let _ = x == f16::NAN; + //~^ WARN incorrect NaN comparison + let _ = x != f16::NAN; + //~^ WARN incorrect NaN comparison + + let x = 5f32; + let _ = x == f32::NAN; + //~^ WARN incorrect NaN comparison + let _ = x != f32::NAN; + //~^ WARN incorrect NaN comparison + + let x = 5f64; + let _ = x == f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = x != f64::NAN; + //~^ WARN incorrect NaN comparison + + let x = 5f128; + let _ = x == f128::NAN; + //~^ WARN incorrect NaN comparison + let _ = x != f128::NAN; + //~^ WARN incorrect NaN comparison + + let b = &2.3f32; + if b != &f32::NAN {} + //~^ WARN incorrect NaN comparison + + let b = &2.3f32; + if b != { &f32::NAN } {} + //~^ WARN incorrect NaN comparison + + let _ = + b != { + //~^ WARN incorrect NaN comparison + &f32::NAN + }; + + // Issue #164143: an unsuffixed float is constrained by the `NAN` operand. + // Suggesting `.is_nan()` drops that constraint and does not compile. + let b = &3.3; + if b != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let mut m = &3.3; + if m != &f64::NAN { + //~^ WARN incorrect NaN comparison + m = &1.0; + } + let _ = m; + + let unary = &(-3.3); + if unary != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let block = &{ 3.3 }; + if block != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let (tuple,) = (&3.3,); + if tuple != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let arithmetic = &(3.3 + 0.0); + if arithmetic != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let x = 1.0f64; + if &x != &f64::NAN {} + //~^ WARN incorrect NaN comparison + let p = &x; + let _ = *p == f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = -x == f64::NAN; + //~^ WARN incorrect NaN comparison + + shadowed::check(); + nested_operands(); + macro_paths(); + method_resolution::check(); + + let _ = 3.3 == f64::NAN; + //~^ WARN incorrect NaN comparison + + let _ = &3.3 != &f64::NAN; + //~^ WARN incorrect NaN comparison + + let suffixed = 3.3f64; + let copied = suffixed; + let _ = copied != f64::NAN; + //~^ WARN incorrect NaN comparison + + let ascribed: f64 = 3.3; + let _ = ascribed != f64::NAN; + //~^ WARN incorrect NaN comparison + + parameter(1.0); + parameter_ref(&1.0); + let _ = |x: f64| x != f64::NAN; //~ WARN incorrect NaN comparison + + #[allow(unused_macros)] + macro_rules! nan { () => { f32::NAN }; } + macro_rules! number { () => { 5f32 }; } + + let _ = nan!() == number!(); + //~^ WARN incorrect NaN comparison + let _ = number!() != nan!(); + //~^ WARN incorrect NaN comparison +} + +fn parameter(x: f64) { + let _ = x == f64::NAN; + //~^ WARN incorrect NaN comparison +} + +fn parameter_ref(x: &f32) { + if x != &f32::NAN {} + //~^ WARN incorrect NaN comparison +} + +fn nested_operands() { + let x = 1.0f64; + let _ = &x as &f64 == &f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = { &{ 3.3 } } != &f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = &&&3.3 == &&&f64::NAN; + //~^ WARN incorrect NaN comparison + let b = &&&3.3; + let _ = &&&f64::NAN != b; + //~^ WARN incorrect NaN comparison + let b = &mut 3.3; + let _ = b != &f64::NAN; + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = &(::NAN) == b; + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = b != &{ f64::NAN }; + //~^ WARN incorrect NaN comparison + let b = &&3.3; + let _ = &{ &{ f64::NAN } } == b; + //~^ WARN incorrect NaN comparison + + let b = &(-3.3); + let _ = b != &f16::NAN; + //~^ WARN incorrect NaN comparison + let b = &(3.3 + 0.0); + let _ = b == &f128::NAN; + //~^ WARN incorrect NaN comparison + + macro_rules! borrowed { () => { &3.3 }; } + let _ = borrowed!() != &f64::NAN; + //~^ WARN incorrect NaN comparison +} + +pub type MacroFloat = f64; + +fn macro_paths() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = b != &nan!(); + //~^ WARN incorrect NaN comparison +} + +mod shadowed { + #[allow(dead_code, non_camel_case_types)] + struct f64; + use ::core::primitive::f64 as Float; + + pub fn check() { + let b = &3.3; + if b != &::core::primitive::f64::NAN {} + //~^ WARN incorrect NaN comparison + let c = &4.4; + if c != &Float::NAN {} + //~^ WARN incorrect NaN comparison + let d = &5.5; + if d != &Float::r#NAN {} + //~^ WARN incorrect NaN comparison + } +} + +mod method_resolution { + mod f64 { + pub fn is_nan(_: ::core::primitive::f64) {} + } + + trait IsNan { + fn is_nan(self); + } + + impl IsNan for &f64 { + fn is_nan(self) {} + } + + pub fn check() { + let _: () = f64::is_nan(5.0); + let _: () = (&5f64).is_nan(); + + let x = 5f64; + let _: bool = x == f64::NAN; + //~^ WARN incorrect NaN comparison + + let x = &5f64; + let _: bool = x == &f64::NAN; + //~^ WARN incorrect NaN comparison + } +} diff --git a/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr b/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr new file mode 100644 index 0000000000000..50d5684dbb2c1 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr @@ -0,0 +1,561 @@ +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:10:13 + | +LL | let _ = x == f16::NAN; + | ^^^^^^^^^^^^^ + | + = note: `#[warn(invalid_nan_comparisons)]` on by default +help: use the `is_nan` method instead + | +LL - let _ = x == f16::NAN; +LL + let _ = ::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:12:13 + | +LL | let _ = x != f16::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x != f16::NAN; +LL + let _ = !::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:16:13 + | +LL | let _ = x == f32::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x == f32::NAN; +LL + let _ = ::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:18:13 + | +LL | let _ = x != f32::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x != f32::NAN; +LL + let _ = !::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:22:13 + | +LL | let _ = x == f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x == f64::NAN; +LL + let _ = ::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:24:13 + | +LL | let _ = x != f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x != f64::NAN; +LL + let _ = !::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:28:13 + | +LL | let _ = x == f128::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x == f128::NAN; +LL + let _ = ::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:30:13 + | +LL | let _ = x != f128::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x != f128::NAN; +LL + let _ = !::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:34:8 + | +LL | if b != &f32::NAN {} + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if b != &f32::NAN {} +LL + if !::is_nan(*b) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:38:8 + | +LL | if b != { &f32::NAN } {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if b != { &f32::NAN } {} +LL + if !::is_nan(*b) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:42:9 + | +LL | / b != { +LL | | +LL | | &f32::NAN +LL | | }; + | |_________^ + | +help: use the `is_nan` method instead + | +LL - b != { +LL - +LL - &f32::NAN +LL - }; +LL + !::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:50:8 + | +LL | if b != &f64::NAN {} + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if b != &f64::NAN {} +LL + if !::is_nan(*b) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:54:8 + | +LL | if m != &f64::NAN { + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if m != &f64::NAN { +LL + if !::is_nan(*m) { + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:61:8 + | +LL | if unary != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if unary != &f64::NAN {} +LL + if !::is_nan(*unary) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:65:8 + | +LL | if block != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if block != &f64::NAN {} +LL + if !::is_nan(*block) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:69:8 + | +LL | if tuple != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if tuple != &f64::NAN {} +LL + if !::is_nan(*tuple) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:73:8 + | +LL | if arithmetic != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if arithmetic != &f64::NAN {} +LL + if !::is_nan(*arithmetic) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:77:8 + | +LL | if &x != &f64::NAN {} + | ^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if &x != &f64::NAN {} +LL + if !::is_nan(*&x) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:80:13 + | +LL | let _ = *p == f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = *p == f64::NAN; +LL + let _ = ::is_nan(*p); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:82:13 + | +LL | let _ = -x == f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = -x == f64::NAN; +LL + let _ = ::is_nan(-x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:90:13 + | +LL | let _ = 3.3 == f64::NAN; + | ^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = 3.3 == f64::NAN; +LL + let _ = ::is_nan(3.3); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:93:13 + | +LL | let _ = &3.3 != &f64::NAN; + | ^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &3.3 != &f64::NAN; +LL + let _ = !::is_nan(*&3.3); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:98:13 + | +LL | let _ = copied != f64::NAN; + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = copied != f64::NAN; +LL + let _ = !::is_nan(copied); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:102:13 + | +LL | let _ = ascribed != f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = ascribed != f64::NAN; +LL + let _ = !::is_nan(ascribed); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:107:22 + | +LL | let _ = |x: f64| x != f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = |x: f64| x != f64::NAN; +LL + let _ = |x: f64| !::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:113:13 + | +LL | let _ = nan!() == number!(); + | ^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = nan!() == number!(); +LL + let _ = ::std::primitive::f32::is_nan(number!()); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:115:13 + | +LL | let _ = number!() != nan!(); + | ^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = number!() != nan!(); +LL + let _ = !::std::primitive::f32::is_nan(number!()); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:120:13 + | +LL | let _ = x == f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = x == f64::NAN; +LL + let _ = ::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:125:8 + | +LL | if x != &f32::NAN {} + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if x != &f32::NAN {} +LL + if !::is_nan(*x) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:131:13 + | +LL | let _ = &x as &f64 == &f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &x as &f64 == &f64::NAN; +LL + let _ = ::is_nan(*(&x as &f64)); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:133:13 + | +LL | let _ = { &{ 3.3 } } != &f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = { &{ 3.3 } } != &f64::NAN; +LL + let _ = !::is_nan(*{ &{ 3.3 } }); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:135:13 + | +LL | let _ = &&&3.3 == &&&f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &&&3.3 == &&&f64::NAN; +LL + let _ = ::is_nan(***&&&3.3); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:138:13 + | +LL | let _ = &&&f64::NAN != b; + | ^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &&&f64::NAN != b; +LL + let _ = !::is_nan(***b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:141:13 + | +LL | let _ = b != &f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &f64::NAN; +LL + let _ = !::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:144:13 + | +LL | let _ = &(::NAN) == b; + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &(::NAN) == b; +LL + let _ = ::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:147:13 + | +LL | let _ = b != &{ f64::NAN }; + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &{ f64::NAN }; +LL + let _ = !::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:150:13 + | +LL | let _ = &{ &{ f64::NAN } } == b; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &{ &{ f64::NAN } } == b; +LL + let _ = ::is_nan(**b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:154:13 + | +LL | let _ = b != &f16::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &f16::NAN; +LL + let _ = !::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:157:13 + | +LL | let _ = b == &f128::NAN; + | ^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b == &f128::NAN; +LL + let _ = ::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:161:13 + | +LL | let _ = borrowed!() != &f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = borrowed!() != &f64::NAN; +LL + let _ = !::is_nan(*borrowed!()); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:171:13 + | +LL | let _ = b != &nan!(); + | ^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &nan!(); +LL + let _ = !::std::primitive::f64::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:182:12 + | +LL | if b != &::core::primitive::f64::NAN {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if b != &::core::primitive::f64::NAN {} +LL + if !<::core::primitive::f64>::is_nan(*b) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:185:12 + | +LL | if c != &Float::NAN {} + | ^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if c != &Float::NAN {} +LL + if !::is_nan(*c) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:188:12 + | +LL | if d != &Float::r#NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if d != &Float::r#NAN {} +LL + if !::is_nan(*d) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:211:23 + | +LL | let _: bool = x == f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _: bool = x == f64::NAN; +LL + let _: bool = ::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:215:23 + | +LL | let _: bool = x == &f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _: bool = x == &f64::NAN; +LL + let _: bool = ::is_nan(*x); + | + +warning: 46 warnings emitted + diff --git a/tests/ui/lto/lto-duplicate-symbols.rs b/tests/ui/lto/lto-duplicate-symbols.rs index 08465eb0fb27a..e468fbe4f30a4 100644 --- a/tests/ui/lto/lto-duplicate-symbols.rs +++ b/tests/ui/lto/lto-duplicate-symbols.rs @@ -10,5 +10,4 @@ extern crate lto_duplicate_symbols2; fn main() {} -//~? WARN Linking globals named 'foo': symbol multiply defined -//~? ERROR failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2 +//~? ERROR Linking globals named 'foo': symbol multiply defined diff --git a/tests/ui/lto/lto-duplicate-symbols.stderr b/tests/ui/lto/lto-duplicate-symbols.stderr index 7e421845258a3..0520ac3dee1f7 100644 --- a/tests/ui/lto/lto-duplicate-symbols.stderr +++ b/tests/ui/lto/lto-duplicate-symbols.stderr @@ -1,6 +1,4 @@ -warning: Linking globals named 'foo': symbol multiply defined! +error: Linking globals named 'foo': symbol multiply defined! -error: failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o": - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/target-feature/too-many-reserved-regs.rs b/tests/ui/target-feature/too-many-reserved-regs.rs new file mode 100644 index 0000000000000..f53d6eb2b2251 --- /dev/null +++ b/tests/ui/target-feature/too-many-reserved-regs.rs @@ -0,0 +1,19 @@ +//@ build-fail +//@ add-minicore +//@ ignore-backends: gcc +//@ needs-llvm-components: riscv +//@ compile-flags: --target=riscv64gc-unknown-linux-gnu -Copt-level=3 -Zllvm-target-feature=+reserve-x1,+reserve-x3,+reserve-x4,+reserve-x5,+reserve-x6,+reserve-x7,+reserve-x8,+reserve-x9,+reserve-x11,+reserve-x12,+reserve-x13,+reserve-x14,+reserve-x15,+reserve-x16,+reserve-x17,+reserve-x18,+reserve-x19,+reserve-x20,+reserve-x21,+reserve-x22,+reserve-x23,+reserve-x24,+reserve-x25,+reserve-x26,+reserve-x27,+reserve-x28,+reserve-x29,+reserve-x30,+reserve-x31 + +#![feature(no_core)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[unsafe(no_mangle)] +pub unsafe fn store_val(dst: *mut u32) { + minicore::ptr::write_volatile(dst, 42); +} + +//~? ERROR ran out of registers during register allocation in function 'store_val' diff --git a/tests/ui/target-feature/too-many-reserved-regs.stderr b/tests/ui/target-feature/too-many-reserved-regs.stderr new file mode 100644 index 0000000000000..3a3e3f33abea8 --- /dev/null +++ b/tests/ui/target-feature/too-many-reserved-regs.stderr @@ -0,0 +1,4 @@ +error: :0:0: ran out of registers during register allocation in function 'store_val' + +error: aborting due to 1 previous error +