From bf693d1743434d294b0868ae63334309afeebe95 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 15:24:30 +0000 Subject: [PATCH 1/8] Migrate 'lossy ptr2int cast' diagnostic --- compiler/rustc_hir_typeck/messages.ftl | 5 ++ compiler/rustc_hir_typeck/src/cast.rs | 68 ++++++++++--------------- compiler/rustc_hir_typeck/src/errors.rs | 46 ++++++++++++++++- 3 files changed, 77 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 4be3ea890dc..d3689ff08a9 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -69,6 +69,11 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` +hir_typeck_lossy_provenance_ptr2int = + under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}` + .suggestion = use `.addr()` to obtain the address of a pointer + .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead + hir_typeck_method_call_on_unknown_raw_pointee = cannot call a method on a raw pointer with an unknown pointee type diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index e8d4e6b447f..c8c25eb3c83 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -30,6 +30,7 @@ use super::FnCtxt; +use crate::errors; use crate::type_error_struct; use hir::ExprKind; use rustc_errors::{ @@ -1007,50 +1008,35 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) { - fcx.tcx.struct_span_lint_hir( + let expr_prec = self.expr.precedence().order(); + let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX; + + let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize)); + let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span); + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let expr_span = self.expr_span.shrink_to_lo(); + let sugg = match (needs_parens, needs_cast) { + (true, true) => errors::LossyProvenancePtr2IntSuggestion::NeedsParensCast { + expr_span, + cast_span, + cast_ty, + }, + (true, false) => { + errors::LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span } + } + (false, true) => { + errors::LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_ty } + } + (false, false) => errors::LossyProvenancePtr2IntSuggestion::Other { cast_span }, + }; + + let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg }; + fcx.tcx.emit_spanned_lint( lint::builtin::LOSSY_PROVENANCE_CASTS, self.expr.hir_id, self.span, - DelayDm(|| format!( - "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`", - self.expr_ty, self.cast_ty - )), - |lint| { - let msg = "use `.addr()` to obtain the address of a pointer"; - - let expr_prec = self.expr.precedence().order(); - let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX; - - let scalar_cast = match t_c { - ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(), - _ => format!(" as {}", self.cast_ty), - }; - - let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span); - - if needs_parens { - let suggestions = vec![ - (self.expr_span.shrink_to_lo(), String::from("(")), - (cast_span, format!(").addr(){scalar_cast}")), - ]; - - lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); - } else { - lint.span_suggestion( - cast_span, - msg, - format!(".addr(){scalar_cast}"), - Applicability::MaybeIncorrect, - ); - } - - lint.help( - "if you can't comply with strict provenance and need to expose the pointer \ - provenance you can use `.expose_addr()` instead" - ); - - lint - }, + lint, ); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index c1d7056b1a0..8798ff176ec 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{ AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{ edition::{Edition, LATEST_STABLE_EDITION}, @@ -269,6 +269,50 @@ pub struct LangStartIncorrectRetTy<'tcx> { pub found_ty: Ty<'tcx>, } +#[derive(LintDiagnostic)] +#[diag(hir_typeck_lossy_provenance_ptr2int)] +#[help] +pub struct LossyProvenancePtr2Int<'tcx> { + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, + #[subdiagnostic] + pub sugg: LossyProvenancePtr2IntSuggestion<'tcx>, +} + +#[derive(Subdiagnostic)] +pub enum LossyProvenancePtr2IntSuggestion<'tcx> { + #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")] + NeedsParensCast { + #[suggestion_part(code = "(")] + expr_span: Span, + #[suggestion_part(code = ").addr() as {cast_ty}")] + cast_span: Span, + cast_ty: Ty<'tcx>, + }, + #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")] + NeedsParens { + #[suggestion_part(code = "(")] + expr_span: Span, + #[suggestion_part(code = ").addr()")] + cast_span: Span, + }, + #[suggestion( + hir_typeck_suggestion, + code = ".addr() as {cast_ty}", + applicability = "maybe-incorrect" + )] + NeedsCast { + #[primary_span] + cast_span: Span, + cast_ty: Ty<'tcx>, + }, + #[suggestion(hir_typeck_suggestion, code = ".addr()", applicability = "maybe-incorrect")] + Other { + #[primary_span] + cast_span: Span, + }, +} + #[derive(Subdiagnostic)] pub enum HelpUseLatestEdition { #[help(hir_typeck_help_set_edition_cargo)] From 64961812084fafadeb6779aeb5cff0764f5d49d6 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 15:32:08 +0000 Subject: [PATCH 2/8] Migrate 'lossy int2ptr cast' diagnostic --- compiler/rustc_hir_typeck/messages.ftl | 5 +++++ compiler/rustc_hir_typeck/src/cast.rs | 29 ++++++++----------------- compiler/rustc_hir_typeck/src/errors.rs | 19 ++++++++++++++++ 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index d3689ff08a9..e5215530a30 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -69,6 +69,11 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` +hir_typeck_lossy_provenance_int2ptr = + strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}` + .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address + .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead + hir_typeck_lossy_provenance_ptr2int = under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}` .suggestion = use `.addr()` to obtain the address of a pointer diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index c8c25eb3c83..872a771e800 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1041,29 +1041,18 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { - fcx.tcx.struct_span_lint_hir( + let sugg = errors::LossyProvenanceInt2PtrSuggestion { + lo: self.expr_span.shrink_to_lo(), + hi: self.expr_span.shrink_to_hi().to(self.cast_span), + }; + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg }; + fcx.tcx.emit_spanned_lint( lint::builtin::FUZZY_PROVENANCE_CASTS, self.expr.hir_id, self.span, - DelayDm(|| format!( - "strict provenance disallows casting integer `{}` to pointer `{}`", - self.expr_ty, self.cast_ty - )), - |lint| { - let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address"; - let suggestions = vec![ - (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")), - (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")), - ]; - - lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); - lint.help( - "if you can't comply with strict provenance and don't have a pointer with \ - the correct provenance you can use `std::ptr::from_exposed_addr()` instead" - ); - - lint - }, + lint, ); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 8798ff176ec..fc7a67297e0 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -269,6 +269,25 @@ pub struct LangStartIncorrectRetTy<'tcx> { pub found_ty: Ty<'tcx>, } +#[derive(LintDiagnostic)] +#[diag(hir_typeck_lossy_provenance_int2ptr)] +#[help] +pub struct LossyProvenanceInt2Ptr<'tcx> { + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, + #[subdiagnostic] + pub sugg: LossyProvenanceInt2PtrSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")] +pub struct LossyProvenanceInt2PtrSuggestion { + #[suggestion_part(code = "(...).with_addr(")] + pub lo: Span, + #[suggestion_part(code = ")")] + pub hi: Span, +} + #[derive(LintDiagnostic)] #[diag(hir_typeck_lossy_provenance_ptr2int)] #[help] From dcb3e70861f2958c3925e8398bd3e41a88114398 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 15:39:54 +0000 Subject: [PATCH 3/8] Migrate 'is_empty' diagnostics --- compiler/rustc_hir_typeck/messages.ftl | 6 ++++++ compiler/rustc_hir_typeck/src/cast.rs | 25 +++++++++---------------- compiler/rustc_hir_typeck/src/errors.rs | 22 ++++++++++++++++++++++ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index e5215530a30..fb03b93b249 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -29,6 +29,8 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to ` hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private +hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` + hir_typeck_expected_default_return_type = expected `()` because of default return type hir_typeck_expected_return_type = expected `{$expected}` because of return type @@ -126,5 +128,9 @@ hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field + +hir_typeck_use_is_empty = + consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything + hir_typeck_yield_expr_outside_of_generator = yield expression outside of generator literal diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 872a771e800..9835951f948 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1068,26 +1068,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let Some((deref_ty, _)) = derefed { // Give a note about what the expr derefs to. if deref_ty != self.expr_ty.peel_refs() { - err.span_note( - self.expr_span, - format!( - "this expression `Deref`s to `{}` which implements `is_empty`", - fcx.ty_to_string(deref_ty) - ), - ); + err.subdiagnostic(errors::DerefImplsIsEmpty { + span: self.expr_span, + deref_ty: fcx.ty_to_string(deref_ty), + }); } // Create a multipart suggestion: add `!` and `.is_empty()` in // place of the cast. - let suggestion = vec![ - (self.expr_span.shrink_to_lo(), "!".to_string()), - (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()), - ]; - - err.multipart_suggestion_verbose(format!( - "consider using the `is_empty` method on `{}` to determine if it contains anything", - fcx.ty_to_string(self.expr_ty), - ), suggestion, Applicability::MaybeIncorrect); + err.subdiagnostic(errors::UseIsEmpty { + lo: self.expr_span.shrink_to_lo(), + hi: self.span.with_lo(self.expr_span.hi()), + expr_ty: fcx.ty_to_string(self.expr_ty), + }); } } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index fc7a67297e0..11b555ba095 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -459,6 +459,20 @@ pub struct UnionPatDotDot { pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + hir_typeck_use_is_empty, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub struct UseIsEmpty { + #[suggestion_part(code = "!")] + pub lo: Span, + #[suggestion_part(code = ".is_empty()")] + pub hi: Span, + pub expr_ty: String, +} + #[derive(Diagnostic)] #[diag(hir_typeck_arg_mismatch_indeterminate)] pub struct ArgMismatchIndeterminate { @@ -535,6 +549,14 @@ pub struct CtorIsPrivate { pub def: String, } +#[derive(Subdiagnostic)] +#[note(hir_typeck_deref_is_empty)] +pub struct DerefImplsIsEmpty { + #[primary_span] + pub span: Span, + pub deref_ty: String, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( hir_typeck_convert_using_method, From c2841e2a1eb2712d580ef83cb7986151ece8c516 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 15:54:47 +0000 Subject: [PATCH 4/8] Migrate 'cast to bool' diagnostic --- compiler/rustc_hir_typeck/messages.ftl | 5 +++ compiler/rustc_hir_typeck/src/cast.rs | 32 ++++--------------- compiler/rustc_hir_typeck/src/errors.rs | 23 +++++++++++++ tests/ui/cast/cast-as-bool.rs | 4 +-- tests/ui/cast/cast-as-bool.stderr | 28 +++++++++++++--- tests/ui/cast/cast-rfc0401-2.stderr | 7 +++- tests/ui/error-codes/E0054.stderr | 7 +++- tests/ui/error-festival.stderr | 7 +++- tests/ui/mismatched_types/cast-rfc0401.stderr | 7 +++- 9 files changed, 84 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index fb03b93b249..b1074745d72 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -16,6 +16,11 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}` *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it } +hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` + .suggestion = compare with zero instead + .help = compare with zero instead + .label = unsupported cast + hir_typeck_const_select_must_be_const = this argument must be a `const fn` .help = consult the documentation on `const_eval_select` for more information diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 9835951f948..bb1b7f2534f 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -322,33 +322,13 @@ impl<'a, 'tcx> CastCheck<'tcx> { .emit(); } CastError::CastToBool => { - let mut err = struct_span_err!( - fcx.tcx.sess, - self.span, - E0054, - "cannot cast `{}` as `bool`", - self.expr_ty - ); - - if self.expr_ty.is_numeric() { - match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) { - Ok(snippet) => { - err.span_suggestion( - self.span, - "compare with zero instead", - format!("{snippet} != 0"), - Applicability::MachineApplicable, - ); - } - Err(_) => { - err.span_help(self.span, "compare with zero instead"); - } - } + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let help = if self.expr_ty.is_numeric() { + errors::CannotCastToBoolHelp::Numeric(self.expr_span.shrink_to_hi().with_hi(self.span.hi())) } else { - err.span_label(self.span, "unsupported cast"); - } - - err.emit(); + errors::CannotCastToBoolHelp::Unsupported(self.span) + }; + fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help }); } CastError::CastToChar => { let mut err = type_error_struct!( diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 11b555ba095..3bfe5a22df6 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -541,6 +541,29 @@ pub struct CandidateTraitNote { pub action_or_ty: String, } +#[derive(Diagnostic)] +#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")] +pub struct CannotCastToBool<'tcx> { + #[primary_span] + pub span: Span, + pub expr_ty: Ty<'tcx>, + #[subdiagnostic] + pub help: CannotCastToBoolHelp, +} + +#[derive(Subdiagnostic)] +pub enum CannotCastToBoolHelp { + #[suggestion( + hir_typeck_suggestion, + applicability = "machine-applicable", + code = " != 0", + style = "verbose" + )] + Numeric(#[primary_span] Span), + #[label(hir_typeck_label)] + Unsupported(#[primary_span] Span), +} + #[derive(Diagnostic)] #[diag(hir_typeck_ctor_is_private, code = "E0603")] pub struct CtorIsPrivate { diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs index 750a88f97eb..511a02718fe 100644 --- a/tests/ui/cast/cast-as-bool.rs +++ b/tests/ui/cast/cast-as-bool.rs @@ -1,11 +1,11 @@ fn main() { let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool` //~| HELP compare with zero instead - //~| SUGGESTION 5 != 0 + //~| SUGGESTION != 0 let t = (1 + 2) as bool; //~ ERROR cannot cast `i32` as `bool` //~| HELP compare with zero instead - //~| SUGGESTION (1 + 2) != 0 + //~| SUGGESTION != 0 let _ = 5_u32 as bool; //~ ERROR cannot cast `u32` as `bool` //~| HELP compare with zero instead diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr index 852fb30cc20..4ff56a95e49 100644 --- a/tests/ui/cast/cast-as-bool.stderr +++ b/tests/ui/cast/cast-as-bool.stderr @@ -2,25 +2,45 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-as-bool.rs:2:13 | LL | let u = 5 as bool; - | ^^^^^^^^^ help: compare with zero instead: `5 != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let u = 5 != 0; + | ~~~~ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-as-bool.rs:6:13 | LL | let t = (1 + 2) as bool; - | ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0` + | ^^^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let t = (1 + 2) != 0; + | ~~~~ error[E0054]: cannot cast `u32` as `bool` --> $DIR/cast-as-bool.rs:10:13 | LL | let _ = 5_u32 as bool; - | ^^^^^^^^^^^^^ help: compare with zero instead: `5_u32 != 0` + | ^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 5_u32 != 0; + | ~~~~ error[E0054]: cannot cast `f64` as `bool` --> $DIR/cast-as-bool.rs:13:13 | LL | let _ = 64.0_f64 as bool; - | ^^^^^^^^^^^^^^^^ help: compare with zero instead: `64.0_f64 != 0` + | ^^^^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 64.0_f64 != 0; + | ~~~~ error[E0054]: cannot cast `IntEnum` as `bool` --> $DIR/cast-as-bool.rs:24:13 diff --git a/tests/ui/cast/cast-rfc0401-2.stderr b/tests/ui/cast/cast-rfc0401-2.stderr index 5dc21ca847c..dd90c3a9723 100644 --- a/tests/ui/cast/cast-rfc0401-2.stderr +++ b/tests/ui/cast/cast-rfc0401-2.stderr @@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-rfc0401-2.rs:6:13 | LL | let _ = 3 as bool; - | ^^^^^^^^^ help: compare with zero instead: `3 != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 3 != 0; + | ~~~~ error: aborting due to previous error diff --git a/tests/ui/error-codes/E0054.stderr b/tests/ui/error-codes/E0054.stderr index ea81f4476a7..0a4adabbaf6 100644 --- a/tests/ui/error-codes/E0054.stderr +++ b/tests/ui/error-codes/E0054.stderr @@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/E0054.rs:3:24 | LL | let x_is_nonzero = x as bool; - | ^^^^^^^^^ help: compare with zero instead: `x != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let x_is_nonzero = x != 0; + | ~~~~ error: aborting due to previous error diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr index 74a2bc8d768..9d75671c4e6 100644 --- a/tests/ui/error-festival.stderr +++ b/tests/ui/error-festival.stderr @@ -63,7 +63,12 @@ error[E0054]: cannot cast `{integer}` as `bool` --> $DIR/error-festival.rs:33:24 | LL | let x_is_nonzero = x as bool; - | ^^^^^^^^^ help: compare with zero instead: `x != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let x_is_nonzero = x != 0; + | ~~~~ error[E0606]: casting `&u8` as `u32` is invalid --> $DIR/error-festival.rs:37:18 diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index 0cea60746bf..d63cec48917 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -86,7 +86,12 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-rfc0401.rs:39:13 | LL | let _ = 3_i32 as bool; - | ^^^^^^^^^^^^^ help: compare with zero instead: `3_i32 != 0` + | ^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 3_i32 != 0; + | ~~~~ error[E0054]: cannot cast `E` as `bool` --> $DIR/cast-rfc0401.rs:40:13 From 94920cc6e0e7c855569c226945e988b5b41c9424 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 16:09:30 +0000 Subject: [PATCH 5/8] Migrate 'int to fat pointer' cast diagnostic --- compiler/rustc_hir_typeck/messages.ftl | 7 ++++ compiler/rustc_hir_typeck/src/cast.rs | 45 ++++++++++--------------- compiler/rustc_hir_typeck/src/errors.rs | 14 ++++++++ 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index b1074745d72..8eed5e6eef1 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -64,6 +64,13 @@ hir_typeck_functional_record_update_on_non_struct = hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` +hir_typeck_int_to_fat = cannot cast `{$expr_ty}` to a pointer that {$known_wide -> + [true] is + *[false] may be + } wide +hir_typeck_int_to_fat_label = creating a `{$cast_ty}` requires both an address and {$metadata} +hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` + hir_typeck_invalid_callee = expected function, found {$ty} hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index bb1b7f2534f..808d5ee8bc1 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -324,7 +324,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::CastToBool => { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let help = if self.expr_ty.is_numeric() { - errors::CannotCastToBoolHelp::Numeric(self.expr_span.shrink_to_hi().with_hi(self.span.hi())) + errors::CannotCastToBoolHelp::Numeric( + self.expr_span.shrink_to_hi().with_hi(self.span.hi()), + ) } else { errors::CannotCastToBoolHelp::Unsupported(self.span) }; @@ -517,33 +519,20 @@ impl<'a, 'tcx> CastCheck<'tcx> { .emit(); } CastError::IntToFatCast(known_metadata) => { - let mut err = struct_span_err!( - fcx.tcx.sess, - self.cast_span, - E0606, - "cannot cast `{}` to a pointer that {} wide", - fcx.ty_to_string(self.expr_ty), - if known_metadata.is_some() { "is" } else { "may be" } - ); - - err.span_label( - self.cast_span, - format!( - "creating a `{}` requires both an address and {}", - self.cast_ty, - known_metadata.unwrap_or("type-specific metadata"), - ), - ); - - if fcx.tcx.sess.is_nightly_build() { - err.span_label( - self.expr_span, - "consider casting this expression to `*const ()`, \ - then using `core::ptr::from_raw_parts`", - ); - } - - err.emit(); + let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let expr_ty = fcx.ty_to_string(self.expr_ty); + let metadata = known_metadata.unwrap_or("type-specific metadata"); + let known_wide = known_metadata.is_some(); + let span = self.cast_span; + fcx.tcx.sess.emit_err(errors::IntToWide { + span, + metadata, + expr_ty, + cast_ty, + expr_if_nightly, + known_wide, + }); } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { let unknown_cast_to = match e { diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3bfe5a22df6..fd7bf050664 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -361,6 +361,20 @@ pub struct InvalidCallee { pub ty: String, } +#[derive(Diagnostic)] +#[diag(hir_typeck_int_to_fat, code = "E0606")] +pub struct IntToWide<'tcx> { + #[primary_span] + #[label(hir_typeck_int_to_fat_label)] + pub span: Span, + pub metadata: &'tcx str, + pub expr_ty: String, + pub cast_ty: Ty<'tcx>, + #[label(hir_typeck_int_to_fat_label_nightly)] + pub expr_if_nightly: Option, + pub known_wide: bool, +} + #[derive(Subdiagnostic)] pub enum OptionResultRefMismatch { #[suggestion( From 82471e9f6cb24b88502182ff194e95e201b3054c Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 16:28:55 +0000 Subject: [PATCH 6/8] Migrate 'casting unknown pointer' diagnostic --- compiler/rustc_hir_typeck/messages.ftl | 8 ++++++ compiler/rustc_hir_typeck/src/cast.rs | 33 +++++++-------------- compiler/rustc_hir_typeck/src/errors.rs | 38 +++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 8eed5e6eef1..888bdeb2e5b 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -21,6 +21,14 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` .help = compare with zero instead .label = unsupported cast +hir_typeck_cast_unknown_pointer = cannot cast {$to -> + [true] to + *[false] from + } a pointer of an unknown kind + .label_to = needs more type information + .note = the type information given here is insufficient to check whether the pointer cast is valid + .label_from = the type information given here is insufficient to check whether the pointer cast is valid + hir_typeck_const_select_must_be_const = this argument must be a `const fn` .help = consult the documentation on `const_eval_select` for more information diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 808d5ee8bc1..6e55e6c5a2c 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -33,9 +33,7 @@ use super::FnCtxt; use crate::errors; use crate::type_error_struct; use hir::ExprKind; -use rustc_errors::{ - struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, -}; +use rustc_errors::{Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; @@ -540,27 +538,16 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::UnknownExprPtrKind => false, _ => bug!(), }; - let mut err = struct_span_err!( - fcx.tcx.sess, - if unknown_cast_to { self.cast_span } else { self.span }, - E0641, - "cannot cast {} a pointer of an unknown kind", - if unknown_cast_to { "to" } else { "from" } - ); - if unknown_cast_to { - err.span_label(self.cast_span, "needs more type information"); - err.note( - "the type information given here is insufficient to check whether \ - the pointer cast is valid", - ); + let (span, sub) = if unknown_cast_to { + (self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span)) } else { - err.span_label( - self.span, - "the type information given here is insufficient to check whether \ - the pointer cast is valid", - ); - } - err.emit(); + (self.cast_span, errors::CastUnknownPointerSub::From(self.span)) + }; + fcx.tcx.sess.emit_err(errors::CastUnknownPointer { + span, + to: unknown_cast_to, + sub, + }); } CastError::ForeignNonExhaustiveAdt => { make_invalid_casting_error( diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index fd7bf050664..127a1574a7b 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -565,6 +565,44 @@ pub struct CannotCastToBool<'tcx> { pub help: CannotCastToBoolHelp, } +#[derive(Diagnostic)] +#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")] +pub struct CastUnknownPointer { + #[primary_span] + pub span: Span, + pub to: bool, + #[subdiagnostic] + pub sub: CastUnknownPointerSub, +} + +pub enum CastUnknownPointerSub { + To(Span), + From(Span), +} + +impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, f: F) + where + F: Fn( + &mut Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + match self { + CastUnknownPointerSub::To(span) => { + let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into()); + diag.span_label(span, msg); + let msg = f(diag, crate::fluent_generated::hir_typeck_note.into()); + diag.note(msg); + } + CastUnknownPointerSub::From(span) => { + let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into()); + diag.span_label(span, msg); + } + } + } +} + #[derive(Subdiagnostic)] pub enum CannotCastToBoolHelp { #[suggestion( From 80a9699117f6e118f395086637c951a08b8ef796 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 16:45:18 +0000 Subject: [PATCH 7/8] Migrate 'trivial cast' lint --- compiler/rustc_hir_typeck/messages.ftl | 6 ++++++ compiler/rustc_hir_typeck/src/cast.rs | 27 +++++++------------------ compiler/rustc_hir_typeck/src/errors.rs | 9 +++++++++ 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 888bdeb2e5b..9e96f7a671b 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -145,6 +145,12 @@ hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling ` hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead +hir_typeck_trivial_cast = trivial {$numeric -> + [true] numeric cast + *[false] cast + }: `{$expr_ty}` as `{$cast_ty}` + .help = cast can be replaced by coercion; this might require a temporary variable + hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 6e55e6c5a2c..4cf3e20029b 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -631,31 +631,18 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { - let t_cast = self.cast_ty; - let t_expr = self.expr_ty; - let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() { - ("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS) + let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() { + (true, lint::builtin::TRIVIAL_NUMERIC_CASTS) } else { - ("", lint::builtin::TRIVIAL_CASTS) + (false, lint::builtin::TRIVIAL_CASTS) }; - fcx.tcx.struct_span_lint_hir( + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + fcx.tcx.emit_spanned_lint( lint, self.expr.hir_id, self.span, - DelayDm(|| { - format!( - "trivial {}cast: `{}` as `{}`", - adjective, - fcx.ty_to_string(t_expr), - fcx.ty_to_string(t_cast) - ) - }), - |lint| { - lint.help( - "cast can be replaced by coercion; this might \ - require a temporary variable", - ) - }, + errors::TrivialCast { numeric, expr_ty, cast_ty }, ); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 127a1574a7b..15bd320bf49 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -533,6 +533,15 @@ pub struct SuggestPtrNullMut { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(hir_typeck_trivial_cast)] +#[help] +pub struct TrivialCast<'tcx> { + pub numeric: bool, + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_typeck_no_associated_item, code = "E0599")] pub struct NoAssociatedItem { From 9c5de75ce10fa6fe88f9ec7c133c9a138e09dabc Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 15 Sep 2023 16:48:25 +0000 Subject: [PATCH 8/8] Migrate 'cast enum with drop to int' diagnostic --- compiler/rustc_hir_typeck/messages.ftl | 2 ++ compiler/rustc_hir_typeck/src/cast.rs | 18 +++++++++--------- compiler/rustc_hir_typeck/src/errors.rs | 7 +++++++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 9e96f7a671b..921a5f5154a 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -21,6 +21,8 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` .help = compare with zero instead .label = unsupported cast +hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop` + hir_typeck_cast_unknown_pointer = cannot cast {$to -> [true] to *[false] from diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 4cf3e20029b..fa779701e61 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -33,7 +33,7 @@ use super::FnCtxt; use crate::errors; use crate::type_error_struct; use hir::ExprKind; -use rustc_errors::{Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; @@ -935,17 +935,17 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let ty::Adt(d, _) = self.expr_ty.kind() && d.has_dtor(fcx.tcx) { - fcx.tcx.struct_span_lint_hir( + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + + fcx.tcx.emit_spanned_lint( lint::builtin::CENUM_IMPL_DROP_CAST, self.expr.hir_id, self.span, - DelayDm(|| format!( - "cannot cast enum `{}` into integer `{}` because it implements `Drop`", - self.expr_ty, self.cast_ty - )), - |lint| { - lint - }, + errors::CastEnumDrop { + expr_ty, + cast_ty, + } ); } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 15bd320bf49..7152585d440 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -574,6 +574,13 @@ pub struct CannotCastToBool<'tcx> { pub help: CannotCastToBoolHelp, } +#[derive(LintDiagnostic)] +#[diag(hir_typeck_cast_enum_drop)] +pub struct CastEnumDrop<'tcx> { + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_typeck_cast_unknown_pointer, code = "E0641")] pub struct CastUnknownPointer {