From 9400c2355ff5f0af6ed8ba25dba0b9efc79f4fea Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 7 Jul 2025 14:08:10 +0000 Subject: [PATCH 1/3] Make `NonZero` a lang item --- compiler/rustc_hir/src/lang_items.rs | 2 ++ compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 2 +- library/core/src/num/nonzero.rs | 2 +- .../src/methods/useless_nonzero_new_unchecked.rs | 6 +++--- src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs | 4 ++-- .../clippy_lints/src/operators/arithmetic_side_effects.rs | 3 ++- .../clippy/clippy_lints/src/operators/integer_division.rs | 7 +++---- .../src/transmute/transmute_int_to_non_zero.rs | 4 ++-- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c11db63ba11ff..f94aee2920997 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -426,6 +426,8 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; + NonZero, sym::NonZero, non_zero, Target::Struct, GenericRequirement::Exact(1); + // Experimental lang items for implementing contract pre- and post-condition checking. ContractBuildCheckEnsures, sym::contract_build_check_ensures, contract_build_check_ensures_fn, Target::Fn, GenericRequirement::None; ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index dd6eb73a3a0aa..9e63234de4f95 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2487,7 +2487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return false, }; - if !self.tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + if !self.tcx.is_lang_item(adt.did(), LangItem::NonZero) { return false; } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 11d50e0f89f30..87701702015d5 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -123,7 +123,7 @@ impl_zeroable_primitive!( #[stable(feature = "generic_nonzero", since = "1.79.0")] #[repr(transparent)] #[rustc_nonnull_optimization_guaranteed] -#[rustc_diagnostic_item = "NonZero"] +#[lang = "NonZero"] pub struct NonZero(T::NonZeroInner); macro_rules! impl_nonzero_fmt { diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs index 22df1f3f485e1..cf266998f0fa6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs @@ -2,9 +2,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_inside_always_const_context; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; -use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, QPath, UnsafeSource}; +use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, QPath, UnsafeSource}; use rustc_lint::LateContext; use rustc_span::sym; @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, func: &Expr<' && segment.ident.name == sym::new_unchecked && let [init_arg] = args && is_inside_always_const_context(cx.tcx, expr.hir_id) - && is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::NonZero) + && is_type_lang_item(cx, cx.typeck_results().node_type(ty.hir_id), LangItem::NonZero) && msrv.meets(cx, msrvs::CONST_UNWRAP) { let mut app = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs index 1b8ab1bdedf8a..6864d4b880567 100644 --- a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs +++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use clippy_utils::sym; use rustc_ast::ast::BinOpKind; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; @@ -81,7 +81,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit // Check if the receiver type is a NonZero type if let ty::Adt(adt_def, _) = receiver_ty.kind() && adt_def.is_struct() - && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) + && cx.tcx.is_lang_item(adt_def.did(), LangItem::NonZero) && let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { let arg_snippet = get_arg_snippet(cx, arg, rcv_path); 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 a78a342d4fe39..8556621978aaa 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 @@ -5,6 +5,7 @@ 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 rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::LangItem; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; @@ -102,7 +103,7 @@ impl ArithmeticSideEffects { let ty::Adt(adt, substs) = ty.kind() else { return false }; - if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + if !tcx.is_lang_item(adt.did(), LangItem::NonZero) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs index 7b98afa9b40bd..850993087f041 100644 --- a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs +++ b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::is_type_diagnostic_item; -use rustc_hir as hir; +use clippy_utils::ty::is_type_lang_item; +use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use super::INTEGER_DIVISION; @@ -16,7 +15,7 @@ pub(crate) fn check<'tcx>( if op == hir::BinOpKind::Div && cx.typeck_results().expr_ty(left).is_integral() && let right_ty = cx.typeck_results().expr_ty(right) - && (right_ty.is_integral() || is_type_diagnostic_item(cx, right_ty, sym::NonZero)) + && (right_ty.is_integral() || is_type_lang_item(cx, right_ty, LangItem::NonZero)) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index f27aaa2fa77aa..41b121307c4c6 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -2,7 +2,7 @@ use super::TRANSMUTE_INT_TO_NON_ZERO; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( return false; }; - if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + if !tcx.is_lang_item(adt.did(), LangItem::NonZero) { return false; } From ab2eecce5a668cfe9ebe4663cde437ee0df81360 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 7 Jul 2025 14:08:10 +0000 Subject: [PATCH 2/3] Add some `NonZero` tests --- .../mismatched_types/non_zero_assigned_lit.rs | 8 + .../non_zero_assigned_lit.stderr | 18 ++ .../non_zero_assigned_oflo_lit.rs | 14 ++ .../non_zero_assigned_oflo_lit.stderr | 48 +++++ .../non_zero_assigned_something.rs | 40 ++++ .../non_zero_assigned_something.stderr | 180 +++++++++++++++++- 6 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 tests/ui/mismatched_types/non_zero_assigned_lit.rs create mode 100644 tests/ui/mismatched_types/non_zero_assigned_lit.stderr create mode 100644 tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs create mode 100644 tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr diff --git a/tests/ui/mismatched_types/non_zero_assigned_lit.rs b/tests/ui/mismatched_types/non_zero_assigned_lit.rs new file mode 100644 index 0000000000000..9c4814b5bfdf6 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_lit.rs @@ -0,0 +1,8 @@ +#![allow(overflowing_literals)] + +fn main() { + let x: std::num::NonZero = -128; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + assert_eq!(x.get(), -128_i8); +} diff --git a/tests/ui/mismatched_types/non_zero_assigned_lit.stderr b/tests/ui/mismatched_types/non_zero_assigned_lit.stderr new file mode 100644 index 0000000000000..2e0f6486810f2 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_lit.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_lit.rs:4:36 + | +LL | let x: std::num::NonZero = -128; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let x: std::num::NonZero = NonZero::new(-128).unwrap(); + | +++++++++++++ ++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs new file mode 100644 index 0000000000000..c66991b512cbc --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs @@ -0,0 +1,14 @@ +#![allow(overflowing_literals)] + +fn main() { + let _: std::num::NonZero = 256; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = -128; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = -129; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` +} diff --git a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr new file mode 100644 index 0000000000000..cfcae44db0af0 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr @@ -0,0 +1,48 @@ +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_oflo_lit.rs:4:36 + | +LL | let _: std::num::NonZero = 256; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(256).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_oflo_lit.rs:8:36 + | +LL | let _: std::num::NonZero = -128; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-128).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_oflo_lit.rs:11:36 + | +LL | let _: std::num::NonZero = -129; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-129).unwrap(); + | +++++++++++++ ++++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.rs b/tests/ui/mismatched_types/non_zero_assigned_something.rs index e94d5249d6a84..51322a88a2115 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.rs +++ b/tests/ui/mismatched_types/non_zero_assigned_something.rs @@ -1,7 +1,47 @@ fn main() { + let _: std::num::NonZero = 0; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: Option> = 0; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 1; //~^ ERROR mismatched types //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 1u8; + //~^ ERROR mismatched types + let _: std::num::NonZero = 1u64; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = 255; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 256; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = -10; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = -128; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = -129; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = -1; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 0; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 1; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` let _: Option> = 1; //~^ ERROR mismatched types diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.stderr b/tests/ui/mismatched_types/non_zero_assigned_something.stderr index aa015bd2efcc9..f50d2960f8686 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.stderr +++ b/tests/ui/mismatched_types/non_zero_assigned_something.stderr @@ -1,6 +1,36 @@ error[E0308]: mismatched types --> $DIR/non_zero_assigned_something.rs:2:37 | +LL | let _: std::num::NonZero = 0; + | ---------------------- ^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(0).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:6:45 + | +LL | let _: Option> = 0; + | ------------------------------ ^ expected `Option>`, found integer + | | + | expected due to this + | + = note: expected enum `Option>` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: Option> = NonZero::new(0); + | +++++++++++++ + + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:10:37 + | LL | let _: std::num::NonZero = 1; | ---------------------- ^ expected `NonZero`, found integer | | @@ -14,7 +44,153 @@ LL | let _: std::num::NonZero = NonZero::new(1).unwrap(); | +++++++++++++ ++++++++++ error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:6:45 + --> $DIR/non_zero_assigned_something.rs:13:37 + | +LL | let _: std::num::NonZero = 1u8; + | ---------------------- ^^^ expected `NonZero`, found `u8` + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `u8` + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:15:37 + | +LL | let _: std::num::NonZero = 1u64; + | ---------------------- ^^^^ expected `NonZero`, found `u64` + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `u64` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(1u64).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:19:36 + | +LL | let _: std::num::NonZero = 255; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(255).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:22:36 + | +LL | let _: std::num::NonZero = 256; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(256).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:26:36 + | +LL | let _: std::num::NonZero = -10; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-10).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:30:36 + | +LL | let _: std::num::NonZero = -128; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-128).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:33:36 + | +LL | let _: std::num::NonZero = -129; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-129).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:36:36 + | +LL | let _: std::num::NonZero = -1; + | --------------------- ^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-1).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:39:36 + | +LL | let _: std::num::NonZero = 0; + | --------------------- ^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(0).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:42:36 + | +LL | let _: std::num::NonZero = 1; + | --------------------- ^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(1).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:46:45 | LL | let _: Option> = 1; | ------------------------------ ^ expected `Option>`, found integer @@ -28,6 +204,6 @@ help: consider calling `NonZero::new` LL | let _: Option> = NonZero::new(1); | +++++++++++++ + -error: aborting due to 2 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0308`. From 94dadf4da023a5b7f272e3a5b866c481c9cb1d96 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 7 Jul 2025 14:08:10 +0000 Subject: [PATCH 3/3] Allow initializing `NonZero` with literals --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 8 + compiler/rustc_lint/src/lints.rs | 27 +++- compiler/rustc_lint/src/types/literal.rs | 87 +++++++++-- .../src/builder/expr/as_constant.rs | 1 + .../mismatched_types/non_zero_assigned_lit.rs | 4 +- .../non_zero_assigned_lit.stderr | 18 --- .../non_zero_assigned_oflo_lit.rs | 13 +- .../non_zero_assigned_oflo_lit.stderr | 48 ++---- .../non_zero_assigned_something.rs | 27 ++-- .../non_zero_assigned_something.stderr | 138 ++++-------------- 10 files changed, 164 insertions(+), 207 deletions(-) delete mode 100644 tests/ui/mismatched_types/non_zero_assigned_lit.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index eeb8d33ef65c3..d037c2f085972 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1665,6 +1665,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => unreachable!(), } } + ty::Adt(adt, ..) if tcx.is_lang_item(adt.did(), LangItem::NonZero) => { + if i.get() == 0 { + // FIXME: report a nice error + None + } else { + Some(ty) + } + } _ => None, }); opt_ty.unwrap_or_else(|| self.next_int_var()) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 21148833eaf72..c37211dd0c5ca 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -11,7 +11,7 @@ use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; -use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; @@ -1713,6 +1713,19 @@ pub(crate) struct OverflowingInt<'a> { #[subdiagnostic] pub help: Option>, } +#[derive(Diagnostic)] +#[diag(lint_overflowing_int)] +#[note] +pub(crate) struct OverflowingIntError<'a> { + #[primary_span] + pub span: Span, + pub ty: &'a str, + pub lit: String, + pub min: i128, + pub max: u128, + #[subdiagnostic] + pub help: Option>, +} #[derive(Subdiagnostic)] #[help(lint_help)] @@ -1738,6 +1751,18 @@ pub(crate) struct OverflowingUInt<'a> { pub max: u128, } +#[derive(Diagnostic)] +#[diag(lint_overflowing_uint)] +#[note] +pub(crate) struct OverflowingUIntError<'a> { + #[primary_span] + pub span: Span, + pub ty: &'a str, + pub lit: String, + pub min: u128, + pub max: u128, +} + #[derive(LintDiagnostic)] #[diag(lint_overflowing_literal)] #[note] diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index d44f45177bde0..c68228ce55107 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -11,8 +11,9 @@ use crate::LateContext; use crate::context::LintContext; use crate::lints::{ OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub, - OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, - RangeEndpointOutOfRange, UseInclusiveRange, + OverflowingBinHexSub, OverflowingInt, OverflowingIntError, OverflowingIntHelp, + OverflowingLiteral, OverflowingUInt, OverflowingUIntError, RangeEndpointOutOfRange, + UseInclusiveRange, }; use crate::types::{OVERFLOWING_LITERALS, TypeLimits}; @@ -250,6 +251,7 @@ fn lint_int_literal<'tcx>( lit: &hir::Lit, t: ty::IntTy, v: u128, + force_error: bool, ) { let int_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = int_ty_range(int_type); @@ -287,11 +289,22 @@ fn lint_int_literal<'tcx>( let help = get_type_suggestion(cx.typeck_results().node_type(hir_id), v, negative) .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); - cx.emit_span_lint( - OVERFLOWING_LITERALS, - span, - OverflowingInt { ty: t.name_str(), lit, min, max, help }, - ); + if force_error { + cx.tcx.dcx().emit_err(OverflowingIntError { + span, + ty: t.name_str(), + lit, + min, + max, + help, + }); + } else { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + span, + OverflowingInt { ty: t.name_str(), lit, min, max, help }, + ); + } } } @@ -301,6 +314,7 @@ fn lint_uint_literal<'tcx>( span: Span, lit: &hir::Lit, t: ty::UintTy, + force_error: bool, ) { let uint_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = uint_ty_range(uint_type); @@ -344,10 +358,9 @@ fn lint_uint_literal<'tcx>( ); return; } - cx.emit_span_lint( - OVERFLOWING_LITERALS, - span, - OverflowingUInt { + if force_error { + cx.tcx.dcx().emit_err(OverflowingUIntError { + span, ty: t.name_str(), lit: cx .sess() @@ -356,8 +369,23 @@ fn lint_uint_literal<'tcx>( .unwrap_or_else(|_| lit_val.to_string()), min, max, - }, - ); + }); + } else { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + span, + OverflowingUInt { + ty: t.name_str(), + lit: cx + .sess() + .source_map() + .span_to_snippet(lit.span) + .unwrap_or_else(|_| lit_val.to_string()), + min, + max, + }, + ); + } } } @@ -369,18 +397,39 @@ pub(crate) fn lint_literal<'tcx>( lit: &hir::Lit, negated: bool, ) { - match *cx.typeck_results().node_type(hir_id).kind() { + lint_literal_inner( + cx, + type_limits, + hir_id, + cx.typeck_results().node_type(hir_id), + span, + lit, + negated, + false, + ) +} +pub(crate) fn lint_literal_inner<'tcx>( + cx: &LateContext<'tcx>, + type_limits: &TypeLimits, + hir_id: HirId, + ty: Ty<'tcx>, + span: Span, + lit: &hir::Lit, + negated: bool, + force_error: bool, +) { + match *ty.kind() { ty::Int(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { - lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get()) + lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get(), force_error) } _ => bug!(), }; } ty::Uint(t) => { assert!(!negated); - lint_uint_literal(cx, hir_id, span, lit, t) + lint_uint_literal(cx, hir_id, span, lit, t, force_error) } ty::Float(t) => { let (is_infinite, sym) = match lit.node { @@ -409,6 +458,12 @@ pub(crate) fn lint_literal<'tcx>( ); } } + ty::Pat(base, ..) if base.is_integral() => { + lint_literal_inner(cx, type_limits, hir_id, base, span, lit, negated, true) + } + ty::Adt(adt, args) if cx.tcx.is_lang_item(adt.did(), hir::LangItem::NonZero) => { + lint_literal_inner(cx, type_limits, hir_id, args.type_at(0), span, lit, negated, true) + } _ => {} } } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index d0d0c21463f85..a85300225040f 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -107,6 +107,7 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> let lit_ty = match *ty.kind() { ty::Pat(base, _) => base, + ty::Adt(adt, args) if tcx.is_lang_item(adt.did(), LangItem::NonZero) => args.type_at(0), _ => ty, }; diff --git a/tests/ui/mismatched_types/non_zero_assigned_lit.rs b/tests/ui/mismatched_types/non_zero_assigned_lit.rs index 9c4814b5bfdf6..f55c724ee7c93 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_lit.rs +++ b/tests/ui/mismatched_types/non_zero_assigned_lit.rs @@ -1,8 +1,8 @@ +//@ check-pass + #![allow(overflowing_literals)] fn main() { let x: std::num::NonZero = -128; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` assert_eq!(x.get(), -128_i8); } diff --git a/tests/ui/mismatched_types/non_zero_assigned_lit.stderr b/tests/ui/mismatched_types/non_zero_assigned_lit.stderr deleted file mode 100644 index 2e0f6486810f2..0000000000000 --- a/tests/ui/mismatched_types/non_zero_assigned_lit.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_lit.rs:4:36 - | -LL | let x: std::num::NonZero = -128; - | --------------------- ^^^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let x: std::num::NonZero = NonZero::new(-128).unwrap(); - | +++++++++++++ ++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs index c66991b512cbc..d9445396a5b88 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs +++ b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs @@ -1,14 +1,15 @@ +//! Ensure overflowing literals are not allowed for +//! layout constrained types like `NonZero`, as that makes +//! it harder to perform the layout checks. Instead +//! we hard error if such literals are out of range. + #![allow(overflowing_literals)] fn main() { let _: std::num::NonZero = 256; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` + //~^ ERROR literal out of range let _: std::num::NonZero = -128; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` let _: std::num::NonZero = -129; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` + //~^ ERROR literal out of range } diff --git a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr index cfcae44db0af0..95b8fafb8dc22 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr +++ b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr @@ -1,48 +1,18 @@ -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_oflo_lit.rs:4:36 +error: literal out of range for `u8` + --> $DIR/non_zero_assigned_oflo_lit.rs:9:36 | LL | let _: std::num::NonZero = 256; - | --------------------- ^^^ expected `NonZero`, found integer - | | - | expected due to this + | ^^^ | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(256).unwrap(); - | +++++++++++++ ++++++++++ - -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_oflo_lit.rs:8:36 - | -LL | let _: std::num::NonZero = -128; - | --------------------- ^^^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(-128).unwrap(); - | +++++++++++++ ++++++++++ + = note: the literal `256` does not fit into the type `u8` whose range is `0..=255` -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_oflo_lit.rs:11:36 +error: literal out of range for `i8` + --> $DIR/non_zero_assigned_oflo_lit.rs:13:36 | LL | let _: std::num::NonZero = -129; - | --------------------- ^^^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` + | ^^^^ | -LL | let _: std::num::NonZero = NonZero::new(-129).unwrap(); - | +++++++++++++ ++++++++++ + = note: the literal `-129` does not fit into the type `i8` whose range is `-128..=127` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.rs b/tests/ui/mismatched_types/non_zero_assigned_something.rs index 51322a88a2115..8c34e513ebb5c 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.rs +++ b/tests/ui/mismatched_types/non_zero_assigned_something.rs @@ -7,9 +7,15 @@ fn main() { //~^ ERROR mismatched types //~| HELP consider calling `NonZero::new` - let _: std::num::NonZero = 1; + let _: std::num::NonZero = 0; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: Option> = 0; //~^ ERROR mismatched types //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = 1; let _: std::num::NonZero = 1u8; //~^ ERROR mismatched types let _: std::num::NonZero = 1u64; @@ -17,31 +23,18 @@ fn main() { //~| HELP consider calling `NonZero::new` let _: std::num::NonZero = 255; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` - let _: std::num::NonZero = 256; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 256; // errors only if no other errors occurred let _: std::num::NonZero = -10; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` + //~^ ERROR cannot apply unary operator `-` to type `NonZero` let _: std::num::NonZero = -128; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` - let _: std::num::NonZero = -129; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = -129; // errors only if no other errors occurred let _: std::num::NonZero = -1; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` let _: std::num::NonZero = 0; //~^ ERROR mismatched types //~| HELP consider calling `NonZero::new` let _: std::num::NonZero = 1; - //~^ ERROR mismatched types - //~| HELP consider calling `NonZero::new` let _: Option> = 1; //~^ ERROR mismatched types diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.stderr b/tests/ui/mismatched_types/non_zero_assigned_something.stderr index f50d2960f8686..7137b350c7658 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.stderr +++ b/tests/ui/mismatched_types/non_zero_assigned_something.stderr @@ -31,7 +31,7 @@ LL | let _: Option> = NonZero::new(0); error[E0308]: mismatched types --> $DIR/non_zero_assigned_something.rs:10:37 | -LL | let _: std::num::NonZero = 1; +LL | let _: std::num::NonZero = 0; | ---------------------- ^ expected `NonZero`, found integer | | | expected due to this @@ -40,11 +40,26 @@ LL | let _: std::num::NonZero = 1; found type `{integer}` help: consider calling `NonZero::new` | -LL | let _: std::num::NonZero = NonZero::new(1).unwrap(); +LL | let _: std::num::NonZero = NonZero::new(0).unwrap(); | +++++++++++++ ++++++++++ error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:13:37 + --> $DIR/non_zero_assigned_something.rs:14:45 + | +LL | let _: Option> = 0; + | ------------------------------ ^ expected `Option>`, found integer + | | + | expected due to this + | + = note: expected enum `Option>` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: Option> = NonZero::new(0); + | +++++++++++++ + + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:19:37 | LL | let _: std::num::NonZero = 1u8; | ---------------------- ^^^ expected `NonZero`, found `u8` @@ -55,7 +70,7 @@ LL | let _: std::num::NonZero = 1u8; found type `u8` error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:15:37 + --> $DIR/non_zero_assigned_something.rs:21:37 | LL | let _: std::num::NonZero = 1u64; | ---------------------- ^^^^ expected `NonZero`, found `u64` @@ -69,98 +84,19 @@ help: consider calling `NonZero::new` LL | let _: std::num::NonZero = NonZero::new(1u64).unwrap(); | +++++++++++++ ++++++++++ -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:19:36 - | -LL | let _: std::num::NonZero = 255; - | --------------------- ^^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(255).unwrap(); - | +++++++++++++ ++++++++++ - -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:22:36 - | -LL | let _: std::num::NonZero = 256; - | --------------------- ^^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(256).unwrap(); - | +++++++++++++ ++++++++++ - -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:26:36 +error[E0600]: cannot apply unary operator `-` to type `NonZero` + --> $DIR/non_zero_assigned_something.rs:28:36 | LL | let _: std::num::NonZero = -10; - | --------------------- ^^^ expected `NonZero`, found integer - | | - | expected due to this + | ^^^ cannot apply unary operator `-` | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` +note: the foreign item type `NonZero` doesn't implement `Neg` + --> $SRC_DIR/core/src/num/nonzero.rs:LL:COL | -LL | let _: std::num::NonZero = NonZero::new(-10).unwrap(); - | +++++++++++++ ++++++++++ + = note: not implement `Neg` error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:30:36 - | -LL | let _: std::num::NonZero = -128; - | --------------------- ^^^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(-128).unwrap(); - | +++++++++++++ ++++++++++ - -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:33:36 - | -LL | let _: std::num::NonZero = -129; - | --------------------- ^^^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(-129).unwrap(); - | +++++++++++++ ++++++++++ - -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:36:36 - | -LL | let _: std::num::NonZero = -1; - | --------------------- ^^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(-1).unwrap(); - | +++++++++++++ ++++++++++ - -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:39:36 + --> $DIR/non_zero_assigned_something.rs:34:36 | LL | let _: std::num::NonZero = 0; | --------------------- ^ expected `NonZero`, found integer @@ -175,22 +111,7 @@ LL | let _: std::num::NonZero = NonZero::new(0).unwrap(); | +++++++++++++ ++++++++++ error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:42:36 - | -LL | let _: std::num::NonZero = 1; - | --------------------- ^ expected `NonZero`, found integer - | | - | expected due to this - | - = note: expected struct `NonZero` - found type `{integer}` -help: consider calling `NonZero::new` - | -LL | let _: std::num::NonZero = NonZero::new(1).unwrap(); - | +++++++++++++ ++++++++++ - -error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:46:45 + --> $DIR/non_zero_assigned_something.rs:39:45 | LL | let _: Option> = 1; | ------------------------------ ^ expected `Option>`, found integer @@ -204,6 +125,7 @@ help: consider calling `NonZero::new` LL | let _: Option> = NonZero::new(1); | +++++++++++++ + -error: aborting due to 14 previous errors +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0600. +For more information about an error, try `rustc --explain E0308`.