From 8e32dade71ad57978786537ec41c13222fd14611 Mon Sep 17 00:00:00 2001 From: bohan Date: Sun, 30 Jul 2023 15:49:33 +0800 Subject: [PATCH 01/19] parser: more friendly hints for handling `async move` in the 2015 edition --- compiler/rustc_parse/messages.ftl | 2 ++ compiler/rustc_parse/src/errors.rs | 7 +++++++ compiler/rustc_parse/src/parser/diagnostics.rs | 15 +++++++++++---- tests/ui/parser/issues/issue-114219.rs | 4 ++++ tests/ui/parser/issues/issue-114219.stderr | 8 ++++++++ 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 tests/ui/parser/issues/issue-114219.rs create mode 100644 tests/ui/parser/issues/issue-114219.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 83d96ad8e7665..aec27060feda2 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -23,6 +23,8 @@ parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or late parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 .label = to use `async fn`, switch to Rust 2018 or later +parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later + parse_async_move_order_incorrect = the order of `move` and `async` is incorrect .suggestion = try switching the order diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 06c0996072730..8ac30a6a5fef2 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1434,6 +1434,13 @@ pub(crate) struct AsyncBlockIn2015 { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_move_block_in_2015)] +pub(crate) struct AsyncMoveBlockIn2015 { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_self_argument_pointer)] pub(crate) struct SelfArgumentPointer { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e6de51a673c85..6156ebec2306c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -4,10 +4,11 @@ use super::{ TokenExpectType, TokenType, }; use crate::errors::{ - AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, - ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, - DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus, + BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, + ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, + ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, + DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, @@ -573,6 +574,12 @@ impl<'a> Parser<'a> { return Err(self.sess.create_err(UseEqInstead { span: self.token.span })); } + if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { + // The 2015 edition is in use because parsing of `async move` has failed. + let span = self.prev_token.span.to(self.token.span); + return Err(self.sess.create_err(AsyncMoveBlockIn2015 { span })); + } + let expect = tokens_to_string(&expected); let actual = super::token_descr(&self.token); let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { diff --git a/tests/ui/parser/issues/issue-114219.rs b/tests/ui/parser/issues/issue-114219.rs new file mode 100644 index 0000000000000..332258b628c37 --- /dev/null +++ b/tests/ui/parser/issues/issue-114219.rs @@ -0,0 +1,4 @@ +fn main() { + async move {}; + //~^ ERROR `async move` blocks are only allowed in Rust 2018 or later +} diff --git a/tests/ui/parser/issues/issue-114219.stderr b/tests/ui/parser/issues/issue-114219.stderr new file mode 100644 index 0000000000000..90dcdc427757b --- /dev/null +++ b/tests/ui/parser/issues/issue-114219.stderr @@ -0,0 +1,8 @@ +error: `async move` blocks are only allowed in Rust 2018 or later + --> $DIR/issue-114219.rs:2:5 + | +LL | async move {}; + | ^^^^^^^^^^ + +error: aborting due to previous error + From 049c728c60f7c950b7185f0f277609694a8e2a16 Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Tue, 1 Aug 2023 23:30:40 +0800 Subject: [PATCH 02/19] Suggests turbofish in patterns --- compiler/rustc_parse/messages.ftl | 2 ++ compiler/rustc_parse/src/errors.rs | 14 ++++++++ compiler/rustc_parse/src/parser/pat.rs | 1 + compiler/rustc_parse/src/parser/path.rs | 10 +++++- tests/ui/did_you_mean/issue-114112.rs | 11 +++++++ tests/ui/did_you_mean/issue-114112.stderr | 13 ++++++++ tests/ui/parser/issues/issue-22647.rs | 2 +- tests/ui/parser/issues/issue-22647.stderr | 9 ++++-- tests/ui/parser/issues/issue-22712.rs | 2 +- tests/ui/parser/issues/issue-22712.stderr | 9 ++++-- tests/ui/parser/pat-lt-bracket-3.rs | 3 +- tests/ui/parser/pat-lt-bracket-3.stderr | 9 ++++-- tests/ui/parser/pat-lt-bracket-4.rs | 2 +- tests/ui/parser/pat-lt-bracket-4.stderr | 9 ++++-- tests/ui/span/issue-34264.rs | 2 +- tests/ui/span/issue-34264.stderr | 15 +++------ tests/ui/suggestions/issue-64252-self-type.rs | 6 ++-- .../suggestions/issue-64252-self-type.stderr | 32 +++++++------------ 18 files changed, 101 insertions(+), 50 deletions(-) create mode 100644 tests/ui/did_you_mean/issue-114112.rs create mode 100644 tests/ui/did_you_mean/issue-114112.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 83d96ad8e7665..6a9a5a239e48a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -270,6 +270,8 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}` parse_function_body_equals_expr = function body cannot be `= expression;` .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` +parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax + parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets .suggestion = surround the type parameters with angle brackets diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 06c0996072730..3184ca777cef2 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2731,3 +2731,17 @@ pub(crate) struct WhereClauseBeforeConstBodySugg { #[suggestion_part(code = "")] pub right: Span, } + +#[derive(Diagnostic)] +#[diag(parse_generic_args_in_pat_require_turbofish_syntax)] +pub(crate) struct GenericArgsInPatRequireTurbofishSyntax { + #[primary_span] + pub span: Span, + #[suggestion( + parse_sugg_turbofish_syntax, + style = "verbose", + code = "::", + applicability = "maybe-incorrect" + )] + pub suggest_turbofish: Span, +} diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 14891c45d81a2..e0539c4ac04dc 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -805,6 +805,7 @@ impl<'a> Parser<'a> { | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. | token::ModSep // A tuple / struct variant pattern. | token::Not)) // A macro expanding to a pattern. + && !(self.look_ahead(1, |t| t.kind == token::Lt) && self.look_ahead(2, |t| t.can_begin_type())) // May suggest the turbofish syntax for generics, only valid for recoveries. } /// Parses `ident` or `ident @ pat`. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index feb7e829caf68..4fe8a5aa62609 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,6 +1,6 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::errors::PathSingleColon; +use crate::errors::{GenericArgsInPatRequireTurbofishSyntax, PathSingleColon}; use crate::{errors, maybe_whole}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -382,6 +382,14 @@ impl<'a> Parser<'a> { }; PathSegment { ident, args: Some(args), id: ast::DUMMY_NODE_ID } + } else if style == PathStyle::Pat + && self.check_noexpect(&token::Lt) + && self.look_ahead(1, |t| t.can_begin_type()) + { + return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax { + span: self.token.span, + suggest_turbofish: self.token.span.shrink_to_lo(), + })); } else { // Generic arguments are not found. PathSegment::from_ident(ident) diff --git a/tests/ui/did_you_mean/issue-114112.rs b/tests/ui/did_you_mean/issue-114112.rs new file mode 100644 index 0000000000000..0fde12ecd788f --- /dev/null +++ b/tests/ui/did_you_mean/issue-114112.rs @@ -0,0 +1,11 @@ +enum E { + A(T) +} + +fn main() { + match E::::A(1) { + E::A(v) => { //~ ERROR generic args in patterns require the turbofish syntax + println!("{v:?}"); + }, + } +} diff --git a/tests/ui/did_you_mean/issue-114112.stderr b/tests/ui/did_you_mean/issue-114112.stderr new file mode 100644 index 0000000000000..d76b5f72e30cf --- /dev/null +++ b/tests/ui/did_you_mean/issue-114112.stderr @@ -0,0 +1,13 @@ +error: generic args in patterns require the turbofish syntax + --> $DIR/issue-114112.rs:7:10 + | +LL | E::A(v) => { + | ^ + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | E::::A(v) => { + | ++ + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-22647.rs b/tests/ui/parser/issues/issue-22647.rs index a6861410682cb..163cbc69ddd62 100644 --- a/tests/ui/parser/issues/issue-22647.rs +++ b/tests/ui/parser/issues/issue-22647.rs @@ -1,5 +1,5 @@ fn main() { - let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` + let caller = |f: F| //~ ERROR generic args in patterns require the turbofish syntax where F: Fn() -> i32 { let x = f(); diff --git a/tests/ui/parser/issues/issue-22647.stderr b/tests/ui/parser/issues/issue-22647.stderr index 89b454d1973d5..585e70266619a 100644 --- a/tests/ui/parser/issues/issue-22647.stderr +++ b/tests/ui/parser/issues/issue-22647.stderr @@ -1,8 +1,13 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` +error: generic args in patterns require the turbofish syntax --> $DIR/issue-22647.rs:2:15 | LL | let caller = |f: F| - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^ + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | let caller:: = |f: F| + | ++ error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-22712.rs b/tests/ui/parser/issues/issue-22712.rs index 774de9c7e6448..92b12b8e1934c 100644 --- a/tests/ui/parser/issues/issue-22712.rs +++ b/tests/ui/parser/issues/issue-22712.rs @@ -3,7 +3,7 @@ struct Foo { } fn bar() { - let Foo> //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` + let Foo> //~ ERROR generic args in patterns require the turbofish syntax } fn main() {} diff --git a/tests/ui/parser/issues/issue-22712.stderr b/tests/ui/parser/issues/issue-22712.stderr index 30fabac65640c..7f9d99d8edfa1 100644 --- a/tests/ui/parser/issues/issue-22712.stderr +++ b/tests/ui/parser/issues/issue-22712.stderr @@ -1,8 +1,13 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` +error: generic args in patterns require the turbofish syntax --> $DIR/issue-22712.rs:6:12 | LL | let Foo> - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^ + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | let Foo::> + | ++ error: aborting due to previous error diff --git a/tests/ui/parser/pat-lt-bracket-3.rs b/tests/ui/parser/pat-lt-bracket-3.rs index a8bdfd3fa181b..bd83fe8db4b56 100644 --- a/tests/ui/parser/pat-lt-bracket-3.rs +++ b/tests/ui/parser/pat-lt-bracket-3.rs @@ -3,8 +3,7 @@ struct Foo(T, T); impl Foo { fn foo(&self) { match *self { - Foo(x, y) => { - //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<` + Foo(x, y) => { //~ ERROR generic args in patterns require the turbofish syntax println!("Goodbye, World!") } } diff --git a/tests/ui/parser/pat-lt-bracket-3.stderr b/tests/ui/parser/pat-lt-bracket-3.stderr index bacf868e3c4e7..afdf1e9a55762 100644 --- a/tests/ui/parser/pat-lt-bracket-3.stderr +++ b/tests/ui/parser/pat-lt-bracket-3.stderr @@ -1,8 +1,13 @@ -error: expected one of `=>`, `@`, `if`, or `|`, found `<` +error: generic args in patterns require the turbofish syntax --> $DIR/pat-lt-bracket-3.rs:6:16 | LL | Foo(x, y) => { - | ^ expected one of `=>`, `@`, `if`, or `|` + | ^ + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | Foo::(x, y) => { + | ++ error: aborting due to previous error diff --git a/tests/ui/parser/pat-lt-bracket-4.rs b/tests/ui/parser/pat-lt-bracket-4.rs index de314f6c6412d..6d348b68cd66b 100644 --- a/tests/ui/parser/pat-lt-bracket-4.rs +++ b/tests/ui/parser/pat-lt-bracket-4.rs @@ -5,7 +5,7 @@ enum BtNode { fn main() { let y = match 10 { - Foo::A(value) => value, //~ error: expected one of `=>`, `@`, `if`, or `|`, found `<` + Foo::A(value) => value, //~ ERROR generic args in patterns require the turbofish syntax Foo::B => 7, }; } diff --git a/tests/ui/parser/pat-lt-bracket-4.stderr b/tests/ui/parser/pat-lt-bracket-4.stderr index 911c276b9319a..b71a5ad939e59 100644 --- a/tests/ui/parser/pat-lt-bracket-4.stderr +++ b/tests/ui/parser/pat-lt-bracket-4.stderr @@ -1,8 +1,13 @@ -error: expected one of `=>`, `@`, `if`, or `|`, found `<` +error: generic args in patterns require the turbofish syntax --> $DIR/pat-lt-bracket-4.rs:8:12 | LL | Foo::A(value) => value, - | ^ expected one of `=>`, `@`, `if`, or `|` + | ^ + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | Foo::::A(value) => value, + | ++ error: aborting due to previous error diff --git a/tests/ui/span/issue-34264.rs b/tests/ui/span/issue-34264.rs index 9227ee482dfa5..c7a8440f28401 100644 --- a/tests/ui/span/issue-34264.rs +++ b/tests/ui/span/issue-34264.rs @@ -1,5 +1,5 @@ fn foo(Option, String) {} //~ ERROR expected one of -//~^ ERROR expected one of +//~^ ERROR generic args in patterns require the turbofish syntax fn bar(x, y: usize) {} //~ ERROR expected one of fn main() { diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index f0dea66f6128d..1874d7f853379 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -1,18 +1,13 @@ -error: expected one of `:`, `@`, or `|`, found `<` +error: generic args in patterns require the turbofish syntax --> $DIR/issue-34264.rs:1:14 | LL | fn foo(Option, String) {} - | ^ expected one of `:`, `@`, or `|` + | ^ | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn foo(self: Option, String) {} - | +++++ -help: if this is a type, explicitly ignore the parameter name +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | -LL | fn foo(_: Option, String) {} - | ++ +LL | fn foo(Option::, String) {} + | ++ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 diff --git a/tests/ui/suggestions/issue-64252-self-type.rs b/tests/ui/suggestions/issue-64252-self-type.rs index 128d5e85c22c8..ad25d334507fc 100644 --- a/tests/ui/suggestions/issue-64252-self-type.rs +++ b/tests/ui/suggestions/issue-64252-self-type.rs @@ -1,14 +1,12 @@ // This test checks that a suggestion to add a `self: ` parameter name is provided // to functions where this is applicable. -pub fn foo(Box) { } -//~^ ERROR expected one of `:`, `@`, or `|`, found `<` +pub fn foo(Box) { } //~ ERROR generic args in patterns require the turbofish syntax struct Bar; impl Bar { - fn bar(Box) { } - //~^ ERROR expected one of `:`, `@`, or `|`, found `<` + fn bar(Box) { } //~ ERROR generic args in patterns require the turbofish syntax } fn main() { } diff --git a/tests/ui/suggestions/issue-64252-self-type.stderr b/tests/ui/suggestions/issue-64252-self-type.stderr index c3418dab0e8af..ba5c2da241500 100644 --- a/tests/ui/suggestions/issue-64252-self-type.stderr +++ b/tests/ui/suggestions/issue-64252-self-type.stderr @@ -1,34 +1,24 @@ -error: expected one of `:`, `@`, or `|`, found `<` +error: generic args in patterns require the turbofish syntax --> $DIR/issue-64252-self-type.rs:4:15 | LL | pub fn foo(Box) { } - | ^ expected one of `:`, `@`, or `|` + | ^ | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | -LL | pub fn foo(self: Box) { } - | +++++ -help: if this is a type, explicitly ignore the parameter name - | -LL | pub fn foo(_: Box) { } - | ++ +LL | pub fn foo(Box::) { } + | ++ -error: expected one of `:`, `@`, or `|`, found `<` - --> $DIR/issue-64252-self-type.rs:10:15 +error: generic args in patterns require the turbofish syntax + --> $DIR/issue-64252-self-type.rs:9:15 | LL | fn bar(Box) { } - | ^ expected one of `:`, `@`, or `|` - | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name + | ^ | -LL | fn bar(self: Box) { } - | +++++ -help: if this is a type, explicitly ignore the parameter name +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | -LL | fn bar(_: Box) { } - | ++ +LL | fn bar(Box::) { } + | ++ error: aborting due to 2 previous errors From 743ae5a2eb5be808704dccb97a013add2edcca20 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 12 Jul 2023 16:17:58 +0200 Subject: [PATCH 03/19] Expand incorrect_fn_null_check lint with reference null checking --- compiler/rustc_lint/messages.ftl | 5 +- compiler/rustc_lint/src/fn_null_check.rs | 34 +++++++--- compiler/rustc_lint/src/lints.rs | 14 +++- tests/ui/lint/fn_null_check.rs | 21 ++++++ tests/ui/lint/fn_null_check.stderr | 82 +++++++++++++++++++++--- 5 files changed, 133 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 16e17fc9d6a5c..42748512f663e 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -213,9 +213,12 @@ lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message .rationale = {$rationale} -lint_fn_null_check = function pointers are not nullable, so checking them for null will always return false +lint_fn_null_check_fn_ptr = function pointers are not nullable, so checking them for null will always return false .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value +lint_fn_null_check_ref = references are not nullable, so checking them for null will always return false + .label = expression has type `{$orig_ty}` + lint_for_loops_over_fallibles = for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement .suggestion = consider using `if let` to clear intent diff --git a/compiler/rustc_lint/src/fn_null_check.rs b/compiler/rustc_lint/src/fn_null_check.rs index e3b33463ccfbc..b036c943f5a10 100644 --- a/compiler/rustc_lint/src/fn_null_check.rs +++ b/compiler/rustc_lint/src/fn_null_check.rs @@ -31,7 +31,7 @@ declare_lint! { declare_lint_pass!(IncorrectFnNullChecks => [INCORRECT_FN_NULL_CHECKS]); -fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { +fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option> { let mut expr = expr.peel_blocks(); let mut had_at_least_one_cast = false; while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind @@ -39,7 +39,18 @@ fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { expr = cast_expr.peel_blocks(); had_at_least_one_cast = true; } - had_at_least_one_cast && cx.typeck_results().expr_ty_adjusted(expr).is_fn() + if !had_at_least_one_cast { + None + } else { + let orig_ty = cx.typeck_results().expr_ty(expr); + if orig_ty.is_fn() { + Some(FnNullCheckDiag::FnPtr) + } else if orig_ty.is_ref() { + Some(FnNullCheckDiag::Ref { orig_ty, label: expr.span }) + } else { + None + } + } } impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { @@ -54,9 +65,9 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_const_is_null | sym::ptr_is_null) ) - && is_fn_ptr_cast(cx, arg) => + && let Some(diag) = incorrect_check(cx, arg) => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) } // Catching: @@ -67,17 +78,20 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_const_is_null | sym::ptr_is_null) ) - && is_fn_ptr_cast(cx, receiver) => + && let Some(diag) = incorrect_check(cx, receiver) => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) } ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { let to_check: &Expr<'_>; - if is_fn_ptr_cast(cx, left) { + let diag: FnNullCheckDiag<'_>; + if let Some(ddiag) = incorrect_check(cx, left) { to_check = right; - } else if is_fn_ptr_cast(cx, right) { + diag = ddiag; + } else if let Some(ddiag) = incorrect_check(cx, right) { to_check = left; + diag = ddiag; } else { return; } @@ -89,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { if let ExprKind::Lit(spanned) = cast_expr.kind && let LitKind::Int(v, _) = spanned.node && v == 0 => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) }, // Catching: @@ -100,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) }, _ => {}, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 968172693a93b..5f3b5c702d7ed 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -615,9 +615,17 @@ pub struct ExpectationNote { // fn_null_check.rs #[derive(LintDiagnostic)] -#[diag(lint_fn_null_check)] -#[help] -pub struct FnNullCheckDiag; +pub enum FnNullCheckDiag<'a> { + #[diag(lint_fn_null_check_fn_ptr)] + #[help(lint_help)] + FnPtr, + #[diag(lint_fn_null_check_ref)] + Ref { + orig_ty: Ty<'a>, + #[label] + label: Span, + }, +} // for_loops_over_fallibles.rs #[derive(LintDiagnostic)] diff --git a/tests/ui/lint/fn_null_check.rs b/tests/ui/lint/fn_null_check.rs index 7f01f2c428395..87b120fc131b1 100644 --- a/tests/ui/lint/fn_null_check.rs +++ b/tests/ui/lint/fn_null_check.rs @@ -3,6 +3,7 @@ fn main() { let fn_ptr = main; + // ------------- Function pointers --------------- if (fn_ptr as *mut ()).is_null() {} //~^ WARN function pointers are not nullable if (fn_ptr as *const u8).is_null() {} @@ -20,6 +21,26 @@ fn main() { if (fn_ptr as fn() as *const ()).is_null() {} //~^ WARN function pointers are not nullable + // ---------------- References ------------------ + if (&mut 8 as *mut i32).is_null() {} + //~^ WARN references are not nullable + if (&8 as *const i32).is_null() {} + //~^ WARN references are not nullable + if (&8 as *const i32) == std::ptr::null() {} + //~^ WARN references are not nullable + let ref_num = &8; + if (ref_num as *const i32) == std::ptr::null() {} + //~^ WARN references are not nullable + if (b"\0" as *const u8).is_null() {} + //~^ WARN references are not nullable + if ("aa" as *const str).is_null() {} + //~^ WARN references are not nullable + if (&[1, 2] as *const i32).is_null() {} + //~^ WARN references are not nullable + if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} + //~^ WARN references are not nullable + + // ---------------------------------------------- const ZPTR: *const () = 0 as *const _; const NOT_ZPTR: *const () = 1 as *const _; diff --git a/tests/ui/lint/fn_null_check.stderr b/tests/ui/lint/fn_null_check.stderr index 0398c0da50feb..7a08c5bda2b67 100644 --- a/tests/ui/lint/fn_null_check.stderr +++ b/tests/ui/lint/fn_null_check.stderr @@ -1,5 +1,5 @@ warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:6:8 + --> $DIR/fn_null_check.rs:7:8 | LL | if (fn_ptr as *mut ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | if (fn_ptr as *mut ()).is_null() {} = note: `#[warn(incorrect_fn_null_checks)]` on by default warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:8:8 + --> $DIR/fn_null_check.rs:9:8 | LL | if (fn_ptr as *const u8).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | if (fn_ptr as *const u8).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:10:8 + --> $DIR/fn_null_check.rs:11:8 | LL | if (fn_ptr as *const ()) == std::ptr::null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | if (fn_ptr as *const ()) == std::ptr::null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:12:8 + --> $DIR/fn_null_check.rs:13:8 | LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:14:8 + --> $DIR/fn_null_check.rs:15:8 | LL | if (fn_ptr as *const ()) == (0 as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | if (fn_ptr as *const ()) == (0 as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:16:8 + --> $DIR/fn_null_check.rs:17:8 | LL | if <*const _>::is_null(fn_ptr as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | if <*const _>::is_null(fn_ptr as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:18:8 + --> $DIR/fn_null_check.rs:19:8 | LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,12 +56,76 @@ LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:20:8 + --> $DIR/fn_null_check.rs:21:8 | LL | if (fn_ptr as fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value -warning: 8 warnings emitted +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:25:8 + | +LL | if (&mut 8 as *mut i32).is_null() {} + | ^------^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&mut i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:27:8 + | +LL | if (&8 as *const i32).is_null() {} + | ^--^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:29:8 + | +LL | if (&8 as *const i32) == std::ptr::null() {} + | ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:32:8 + | +LL | if (ref_num as *const i32) == std::ptr::null() {} + | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:34:8 + | +LL | if (b"\0" as *const u8).is_null() {} + | ^-----^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&[u8; 1]` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:36:8 + | +LL | if ("aa" as *const str).is_null() {} + | ^----^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&str` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:38:8 + | +LL | if (&[1, 2] as *const i32).is_null() {} + | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&[i32; 2]` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/fn_null_check.rs:40:8 + | +LL | if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} + | ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&mut [i32; 2]` + +warning: 16 warnings emitted From d2b7c8028f92640421762f0941c42a21d280002e Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 13 Jul 2023 12:01:13 +0200 Subject: [PATCH 04/19] Rename incorrect_fn_null_checks to useless_ptr_null_checks --- compiler/rustc_lint/messages.ftl | 12 +++---- compiler/rustc_lint/src/lib.rs | 6 ++-- compiler/rustc_lint/src/lints.rs | 8 ++--- .../src/{fn_null_check.rs => ptr_nulls.rs} | 34 +++++++++---------- .../{fn_null_check.rs => ptr_null_checks.rs} | 0 ...ll_check.stderr => ptr_null_checks.stderr} | 34 +++++++++---------- 6 files changed, 47 insertions(+), 47 deletions(-) rename compiler/rustc_lint/src/{fn_null_check.rs => ptr_nulls.rs} (78%) rename tests/ui/lint/{fn_null_check.rs => ptr_null_checks.rs} (100%) rename tests/ui/lint/{fn_null_check.stderr => ptr_null_checks.stderr} (88%) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 42748512f663e..4897ffd0cece5 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -213,12 +213,6 @@ lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message .rationale = {$rationale} -lint_fn_null_check_fn_ptr = function pointers are not nullable, so checking them for null will always return false - .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value - -lint_fn_null_check_ref = references are not nullable, so checking them for null will always return false - .label = expression has type `{$orig_ty}` - lint_for_loops_over_fallibles = for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement .suggestion = consider using `if let` to clear intent @@ -453,6 +447,12 @@ lint_path_statement_drop = path statement drops value lint_path_statement_no_effect = path statement with no effect +lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false + .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value + +lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false + .label = expression has type `{$orig_ty}` + lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 53089294fe2e6..0298c24fbbacf 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -57,7 +57,6 @@ mod early; mod enum_intrinsics_non_enums; mod errors; mod expect; -mod fn_null_check; mod for_loops_over_fallibles; pub mod hidden_unicode_codepoints; mod internal; @@ -76,6 +75,7 @@ mod noop_method_call; mod opaque_hidden_inferred_bound; mod pass_by_value; mod passes; +mod ptr_nulls; mod redundant_semicolon; mod reference_casting; mod traits; @@ -102,7 +102,6 @@ use builtin::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; -use fn_null_check::*; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use internal::*; @@ -117,6 +116,7 @@ use nonstandard_style::*; use noop_method_call::*; use opaque_hidden_inferred_bound::*; use pass_by_value::*; +use ptr_nulls::*; use redundant_semicolon::*; use reference_casting::*; use traits::*; @@ -227,7 +227,7 @@ late_lint_methods!( // Depends on types used in type definitions MissingCopyImplementations: MissingCopyImplementations, // Depends on referenced function signatures in expressions - IncorrectFnNullChecks: IncorrectFnNullChecks, + PtrNullChecks: PtrNullChecks, MutableTransmutes: MutableTransmutes, TypeAliasBounds: TypeAliasBounds, TrivialConstraints: TrivialConstraints, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5f3b5c702d7ed..9e1d5605260c3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -613,13 +613,13 @@ pub struct ExpectationNote { pub rationale: Symbol, } -// fn_null_check.rs +// ptr_nulls.rs #[derive(LintDiagnostic)] -pub enum FnNullCheckDiag<'a> { - #[diag(lint_fn_null_check_fn_ptr)] +pub enum PtrNullChecksDiag<'a> { + #[diag(lint_ptr_null_checks_fn_ptr)] #[help(lint_help)] FnPtr, - #[diag(lint_fn_null_check_ref)] + #[diag(lint_ptr_null_checks_ref)] Ref { orig_ty: Ty<'a>, #[label] diff --git a/compiler/rustc_lint/src/fn_null_check.rs b/compiler/rustc_lint/src/ptr_nulls.rs similarity index 78% rename from compiler/rustc_lint/src/fn_null_check.rs rename to compiler/rustc_lint/src/ptr_nulls.rs index b036c943f5a10..b2138c42224b4 100644 --- a/compiler/rustc_lint/src/fn_null_check.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -1,12 +1,12 @@ -use crate::{lints::FnNullCheckDiag, LateContext, LateLintPass, LintContext}; +use crate::{lints::PtrNullChecksDiag, LateContext, LateLintPass, LintContext}; use rustc_ast::LitKind; use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; declare_lint! { - /// The `incorrect_fn_null_checks` lint checks for expression that checks if a - /// function pointer is null. + /// The `useless_ptr_null_checks` lint checks for useless null checks against pointers + /// obtained from non-null types. /// /// ### Example /// @@ -22,16 +22,16 @@ declare_lint! { /// /// ### Explanation /// - /// Function pointers are assumed to be non-null, checking them for null will always - /// return false. - INCORRECT_FN_NULL_CHECKS, + /// Function pointers and references are assumed to be non-null, checking them for null + /// will always return false. + USELESS_PTR_NULL_CHECKS, Warn, - "incorrect checking of null function pointer" + "useless checking of non-null-typed pointer" } -declare_lint_pass!(IncorrectFnNullChecks => [INCORRECT_FN_NULL_CHECKS]); +declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]); -fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option> { +fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option> { let mut expr = expr.peel_blocks(); let mut had_at_least_one_cast = false; while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind @@ -44,16 +44,16 @@ fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option LateLintPass<'tcx> for IncorrectFnNullChecks { +impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match expr.kind { // Catching: @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { ) && let Some(diag) = incorrect_check(cx, arg) => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) + cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } // Catching: @@ -80,12 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { ) && let Some(diag) = incorrect_check(cx, receiver) => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) + cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { let to_check: &Expr<'_>; - let diag: FnNullCheckDiag<'_>; + let diag: PtrNullChecksDiag<'_>; if let Some(ddiag) = incorrect_check(cx, left) { to_check = right; diag = ddiag; @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { if let ExprKind::Lit(spanned) = cast_expr.kind && let LitKind::Int(v, _) = spanned.node && v == 0 => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) + cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) }, // Catching: @@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) => { - cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag) + cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) }, _ => {}, diff --git a/tests/ui/lint/fn_null_check.rs b/tests/ui/lint/ptr_null_checks.rs similarity index 100% rename from tests/ui/lint/fn_null_check.rs rename to tests/ui/lint/ptr_null_checks.rs diff --git a/tests/ui/lint/fn_null_check.stderr b/tests/ui/lint/ptr_null_checks.stderr similarity index 88% rename from tests/ui/lint/fn_null_check.stderr rename to tests/ui/lint/ptr_null_checks.stderr index 7a08c5bda2b67..62ce910c7169b 100644 --- a/tests/ui/lint/fn_null_check.stderr +++ b/tests/ui/lint/ptr_null_checks.stderr @@ -1,14 +1,14 @@ warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:7:8 + --> $DIR/ptr_null_checks.rs:7:8 | LL | if (fn_ptr as *mut ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value - = note: `#[warn(incorrect_fn_null_checks)]` on by default + = note: `#[warn(useless_ptr_null_checks)]` on by default warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:9:8 + --> $DIR/ptr_null_checks.rs:9:8 | LL | if (fn_ptr as *const u8).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | if (fn_ptr as *const u8).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:11:8 + --> $DIR/ptr_null_checks.rs:11:8 | LL | if (fn_ptr as *const ()) == std::ptr::null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | if (fn_ptr as *const ()) == std::ptr::null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:13:8 + --> $DIR/ptr_null_checks.rs:13:8 | LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:15:8 + --> $DIR/ptr_null_checks.rs:15:8 | LL | if (fn_ptr as *const ()) == (0 as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | if (fn_ptr as *const ()) == (0 as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:17:8 + --> $DIR/ptr_null_checks.rs:17:8 | LL | if <*const _>::is_null(fn_ptr as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | if <*const _>::is_null(fn_ptr as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:19:8 + --> $DIR/ptr_null_checks.rs:19:8 | LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:21:8 + --> $DIR/ptr_null_checks.rs:21:8 | LL | if (fn_ptr as fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | if (fn_ptr as fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:25:8 + --> $DIR/ptr_null_checks.rs:25:8 | LL | if (&mut 8 as *mut i32).is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | if (&mut 8 as *mut i32).is_null() {} | expression has type `&mut i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:27:8 + --> $DIR/ptr_null_checks.rs:27:8 | LL | if (&8 as *const i32).is_null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | if (&8 as *const i32).is_null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:29:8 + --> $DIR/ptr_null_checks.rs:29:8 | LL | if (&8 as *const i32) == std::ptr::null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | if (&8 as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:32:8 + --> $DIR/ptr_null_checks.rs:32:8 | LL | if (ref_num as *const i32) == std::ptr::null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | if (ref_num as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:34:8 + --> $DIR/ptr_null_checks.rs:34:8 | LL | if (b"\0" as *const u8).is_null() {} | ^-----^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | if (b"\0" as *const u8).is_null() {} | expression has type `&[u8; 1]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:36:8 + --> $DIR/ptr_null_checks.rs:36:8 | LL | if ("aa" as *const str).is_null() {} | ^----^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | if ("aa" as *const str).is_null() {} | expression has type `&str` warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:38:8 + --> $DIR/ptr_null_checks.rs:38:8 | LL | if (&[1, 2] as *const i32).is_null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | if (&[1, 2] as *const i32).is_null() {} | expression has type `&[i32; 2]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/fn_null_check.rs:40:8 + --> $DIR/ptr_null_checks.rs:40:8 | LL | if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} | ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 84c5372a45f0eeffa3cf8b6bdc0e981c6eea299e Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 13 Jul 2023 12:23:06 +0200 Subject: [PATCH 05/19] Rename incorrect_fn_null_checks to useless_ptr_null_checks (clippy side) --- src/tools/clippy/clippy_lints/src/renamed_lints.rs | 2 +- src/tools/clippy/tests/ui/rename.fixed | 4 ++-- src/tools/clippy/tests/ui/rename.rs | 2 +- src/tools/clippy/tests/ui/rename.stderr | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 49bdc6796049a..fc1fabcc0ae59 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -43,7 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), ("clippy::forget_copy", "forgetting_copy_types"), ("clippy::forget_ref", "forgetting_references"), - ("clippy::fn_null_check", "incorrect_fn_null_checks"), + ("clippy::fn_null_check", "useless_ptr_null_checks"), ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 8ec19b120d127..8257bf2947ab0 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -38,7 +38,7 @@ #![allow(for_loops_over_fallibles)] #![allow(forgetting_copy_types)] #![allow(forgetting_references)] -#![allow(incorrect_fn_null_checks)] +#![allow(useless_ptr_null_checks)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -92,7 +92,7 @@ #![warn(for_loops_over_fallibles)] #![warn(forgetting_copy_types)] #![warn(forgetting_references)] -#![warn(incorrect_fn_null_checks)] +#![warn(useless_ptr_null_checks)] #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 51a5976eb6149..6569dad18d406 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -38,7 +38,7 @@ #![allow(for_loops_over_fallibles)] #![allow(forgetting_copy_types)] #![allow(forgetting_references)] -#![allow(incorrect_fn_null_checks)] +#![allow(useless_ptr_null_checks)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index e420ea1d2adb5..57e991e5695a1 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -246,11 +246,11 @@ error: lint `clippy::forget_ref` has been renamed to `forgetting_references` LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` -error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks` +error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::fn_null_check)] - | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks` + | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` --> $DIR/rename.rs:96:9 From ef3413d423299039cdf807b2e9484e7825cc21cd Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 13 Jul 2023 13:38:31 +0200 Subject: [PATCH 06/19] Add more tests for useless_ptr_null_checks lint --- tests/ui/lint/ptr_null_checks.rs | 9 +++++ tests/ui/lint/ptr_null_checks.stderr | 58 ++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs index 87b120fc131b1..600ca32ca8937 100644 --- a/tests/ui/lint/ptr_null_checks.rs +++ b/tests/ui/lint/ptr_null_checks.rs @@ -1,5 +1,8 @@ // check-pass +extern "C" fn c_fn() {} +fn static_i32() -> &'static i32 { &1 } + fn main() { let fn_ptr = main; @@ -20,6 +23,8 @@ fn main() { //~^ WARN function pointers are not nullable if (fn_ptr as fn() as *const ()).is_null() {} //~^ WARN function pointers are not nullable + if (c_fn as *const fn()).is_null() {} + //~^ WARN function pointers are not nullable // ---------------- References ------------------ if (&mut 8 as *mut i32).is_null() {} @@ -39,6 +44,10 @@ fn main() { //~^ WARN references are not nullable if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} //~^ WARN references are not nullable + if (static_i32() as *const i32).is_null() {} + //~^ WARN references are not nullable + if (&*{ static_i32() } as *const i32).is_null() {} + //~^ WARN references are not nullable // ---------------------------------------------- const ZPTR: *const () = 0 as *const _; diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr index 62ce910c7169b..10efa8685befd 100644 --- a/tests/ui/lint/ptr_null_checks.stderr +++ b/tests/ui/lint/ptr_null_checks.stderr @@ -1,5 +1,5 @@ warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:7:8 + --> $DIR/ptr_null_checks.rs:10:8 | LL | if (fn_ptr as *mut ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | if (fn_ptr as *mut ()).is_null() {} = note: `#[warn(useless_ptr_null_checks)]` on by default warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:9:8 + --> $DIR/ptr_null_checks.rs:12:8 | LL | if (fn_ptr as *const u8).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | if (fn_ptr as *const u8).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:11:8 + --> $DIR/ptr_null_checks.rs:14:8 | LL | if (fn_ptr as *const ()) == std::ptr::null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | if (fn_ptr as *const ()) == std::ptr::null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:13:8 + --> $DIR/ptr_null_checks.rs:16:8 | LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:15:8 + --> $DIR/ptr_null_checks.rs:18:8 | LL | if (fn_ptr as *const ()) == (0 as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | if (fn_ptr as *const ()) == (0 as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:17:8 + --> $DIR/ptr_null_checks.rs:20:8 | LL | if <*const _>::is_null(fn_ptr as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | if <*const _>::is_null(fn_ptr as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:19:8 + --> $DIR/ptr_null_checks.rs:22:8 | LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,15 +56,23 @@ LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:21:8 + --> $DIR/ptr_null_checks.rs:24:8 | LL | if (fn_ptr as fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value +warning: function pointers are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:26:8 + | +LL | if (c_fn as *const fn()).is_null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value + warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:25:8 + --> $DIR/ptr_null_checks.rs:30:8 | LL | if (&mut 8 as *mut i32).is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +80,7 @@ LL | if (&mut 8 as *mut i32).is_null() {} | expression has type `&mut i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:27:8 + --> $DIR/ptr_null_checks.rs:32:8 | LL | if (&8 as *const i32).is_null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +88,7 @@ LL | if (&8 as *const i32).is_null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:29:8 + --> $DIR/ptr_null_checks.rs:34:8 | LL | if (&8 as *const i32) == std::ptr::null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +96,7 @@ LL | if (&8 as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:32:8 + --> $DIR/ptr_null_checks.rs:37:8 | LL | if (ref_num as *const i32) == std::ptr::null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +104,7 @@ LL | if (ref_num as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:34:8 + --> $DIR/ptr_null_checks.rs:39:8 | LL | if (b"\0" as *const u8).is_null() {} | ^-----^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +112,7 @@ LL | if (b"\0" as *const u8).is_null() {} | expression has type `&[u8; 1]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:36:8 + --> $DIR/ptr_null_checks.rs:41:8 | LL | if ("aa" as *const str).is_null() {} | ^----^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +120,7 @@ LL | if ("aa" as *const str).is_null() {} | expression has type `&str` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:38:8 + --> $DIR/ptr_null_checks.rs:43:8 | LL | if (&[1, 2] as *const i32).is_null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,12 +128,28 @@ LL | if (&[1, 2] as *const i32).is_null() {} | expression has type `&[i32; 2]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:40:8 + --> $DIR/ptr_null_checks.rs:45:8 | LL | if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} | ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | expression has type `&mut [i32; 2]` -warning: 16 warnings emitted +warning: references are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:47:8 + | +LL | if (static_i32() as *const i32).is_null() {} + | ^------------^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:49:8 + | +LL | if (&*{ static_i32() } as *const i32).is_null() {} + | ^------------------^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: 19 warnings emitted From 0b9529cca39d86138066012e85cae96ba4a7c253 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 13 Jul 2023 14:11:29 +0200 Subject: [PATCH 07/19] Add diagnostic items for `<*const _>::cast` and `ptr::from_mut` --- compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/ptr/mod.rs | 1 + library/core/src/ptr/mut_ptr.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d3739733c1d10..9cff8a688ff84 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1155,8 +1155,10 @@ symbols! { profiler_builtins, profiler_runtime, ptr, + ptr_cast, ptr_cast_mut, ptr_const_is_null, + ptr_from_mut, ptr_from_ref, ptr_guaranteed_cmp, ptr_is_null, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index acc9ca29d41a1..5f094ac4e7e64 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -710,6 +710,7 @@ pub const fn from_ref(r: &T) -> *const T { #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] +#[rustc_diagnostic_item = "ptr_from_mut"] pub const fn from_mut(r: &mut T) -> *mut T { r } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index e7f27439540b9..e3a3f69afd9a2 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -54,6 +54,7 @@ impl *mut T { /// Casts to a pointer of another type. #[stable(feature = "ptr_cast", since = "1.38.0")] #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")] + #[rustc_diagnostic_item = "ptr_cast"] #[inline(always)] pub const fn cast(self) -> *mut U { self as _ From 60fffbc978965a84145a5c65854aad70d563f827 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Wed, 2 Aug 2023 00:09:54 +0400 Subject: [PATCH 08/19] Temporary remove myself from review rotation --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index a180577a83436..9ac8f4d725e35 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -490,7 +490,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514"] +users_on_vacation = ["jyn514", "WaffleLapkin"] [assign.adhoc_groups] compiler-team = [ From 89b2fe7750eb251c2b621bad1f8d86477d7a1f91 Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Thu, 3 Aug 2023 00:00:56 +0800 Subject: [PATCH 09/19] Keep the suggestion for wrong arbitrary self types --- compiler/rustc_parse/src/parser/attr.rs | 4 +- .../rustc_parse/src/parser/diagnostics.rs | 26 +++++++++---- compiler/rustc_parse/src/parser/expr.rs | 10 ++--- compiler/rustc_parse/src/parser/item.rs | 6 +-- compiler/rustc_parse/src/parser/mod.rs | 6 +-- .../rustc_parse/src/parser/nonterminal.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 36 ++++++++++------- compiler/rustc_parse/src/parser/path.rs | 39 ++++++++++++------- compiler/rustc_parse/src/parser/stmt.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 6 +-- .../anon-params-denied-2018.stderr | 20 +++++++--- tests/ui/span/issue-34264.rs | 2 +- tests/ui/span/issue-34264.stderr | 15 ++++--- tests/ui/suggestions/issue-64252-self-type.rs | 5 +-- .../suggestions/issue-64252-self-type.stderr | 32 +++++++++------ 15 files changed, 133 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ee0abba1c1753..1271bce799d5c 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -260,7 +260,7 @@ impl<'a> Parser<'a> { item } else { let do_parse = |this: &mut Self| { - let path = this.parse_path(PathStyle::Mod)?; + let path = this.parse_path(PathStyle::Mod, None)?; let args = this.parse_attr_args()?; Ok(ast::AttrItem { path, args, tokens: None }) }; @@ -387,7 +387,7 @@ impl<'a> Parser<'a> { } let lo = self.token.span; - let path = self.parse_path(PathStyle::Mod)?; + let path = self.parse_path(PathStyle::Mod, None)?; let kind = self.parse_meta_item_kind()?; let span = lo.to(self.prev_token.span); Ok(ast::MetaItem { path, kind, span }) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 7d04a335c9e0b..8bc4433a9653a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1579,7 +1579,7 @@ impl<'a> Parser<'a> { self.expect(&token::ModSep)?; let mut path = ast::Path { segments: ThinVec::new(), span: DUMMY_SP, tokens: None }; - self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?; + self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None, None)?; path.span = ty_span.to(self.prev_token.span); let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty)); @@ -2019,7 +2019,7 @@ impl<'a> Parser<'a> { { let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)"; - let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) = + let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span, maybe_name) = match pat.kind { PatKind::Ident(_, ident, _) => ( ident, @@ -2029,6 +2029,7 @@ impl<'a> Parser<'a> { pat.span.shrink_to_lo(), pat.span.shrink_to_hi(), pat.span.shrink_to_lo(), + true, ), // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) @@ -2045,11 +2046,22 @@ impl<'a> Parser<'a> { pat.span.shrink_to_lo(), pat.span, pat.span.shrink_to_lo(), + true, ) } _ => unreachable!(), } - } + }, + PatKind::Path(_, ref path) if let Some(segment) = path.segments.last() => ( + segment.ident, + "self: ", + ": TypeName".to_string(), + "_: ", + pat.span.shrink_to_lo(), + pat.span.shrink_to_hi(), + pat.span.shrink_to_lo(), + path.segments.len() == 1, // Avoid suggesting that `fn foo(a::b)` is fixed with a change to `fn foo(a::b: TypeName)`. + ), _ => { // Otherwise, try to get a type and emit a suggestion. if let Some(ty) = pat.to_ty() { @@ -2077,7 +2089,7 @@ impl<'a> Parser<'a> { } // Avoid suggesting that `fn foo(HashMap)` is fixed with a change to // `fn foo(HashMap: TypeName)`. - if self.token != token::Lt { + if self.token != token::Lt && maybe_name { err.span_suggestion( param_span, "if this is a parameter name, give it a type", @@ -2100,7 +2112,7 @@ impl<'a> Parser<'a> { } pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { - let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName))?; + let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -2508,7 +2520,7 @@ impl<'a> Parser<'a> { // Skip the `:`. snapshot_pat.bump(); snapshot_type.bump(); - match snapshot_pat.parse_pat_no_top_alt(expected) { + match snapshot_pat.parse_pat_no_top_alt(expected, None) { Err(inner_err) => { inner_err.cancel(); } @@ -2772,7 +2784,7 @@ impl<'a> Parser<'a> { /// sequence of patterns until `)` is reached. fn skip_pat_list(&mut self) -> PResult<'a, ()> { while !self.check(&token::CloseDelim(Delimiter::Parenthesis)) { - self.parse_pat_no_top_alt(None)?; + self.parse_pat_no_top_alt(None, None)?; if !self.eat(&token::Comma) { return Ok(()); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b54cb8c5a0c10..6dafb8b999b2f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -775,7 +775,7 @@ impl<'a> Parser<'a> { _ => {} } - match self.parse_path(PathStyle::Expr) { + match self.parse_path(PathStyle::Expr, None) { Ok(path) => { let span_after_type = parser_snapshot_after_type.token.span; let expr = mk_expr( @@ -1314,7 +1314,7 @@ impl<'a> Parser<'a> { } let fn_span_lo = self.token.span; - let mut seg = self.parse_path_segment(PathStyle::Expr, None)?; + let mut seg = self.parse_path_segment(PathStyle::Expr, None, None)?; self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]); self.check_turbofish_missing_angle_brackets(&mut seg); @@ -1544,7 +1544,7 @@ impl<'a> Parser<'a> { })?; (Some(qself), path) } else { - (None, self.parse_path(PathStyle::Expr)?) + (None, self.parse_path(PathStyle::Expr, None)?) }; // `!`, as an operator, is prefix, so we know this isn't that. @@ -2338,7 +2338,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName))?; + let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?; let ty = if this.eat(&token::Colon) { this.parse_ty()? } else { @@ -2781,7 +2781,7 @@ impl<'a> Parser<'a> { return None; } let pre_pat_snapshot = self.create_snapshot_for_diagnostic(); - match self.parse_pat_no_top_alt(None) { + match self.parse_pat_no_top_alt(None, None) { Ok(_pat) => { if self.token.kind == token::FatArrow { // Reached arm end. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1301ed3e3882e..d3f756139def3 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -452,7 +452,7 @@ impl<'a> Parser<'a> { /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { - let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` + let path = self.parse_path(PathStyle::Mod, None)?; // `foo::bar` self.expect(&token::Not)?; // `!` match self.parse_delim_args() { // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`. @@ -976,7 +976,7 @@ impl<'a> Parser<'a> { self.parse_use_tree_glob_or_nested()? } else { // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` - prefix = self.parse_path(PathStyle::Mod)?; + prefix = self.parse_path(PathStyle::Mod, None)?; if self.eat(&token::ModSep) { self.parse_use_tree_glob_or_nested()? @@ -987,7 +987,7 @@ impl<'a> Parser<'a> { .emit_err(errors::SingleColonImportPath { span: self.prev_token.span }); // We parse the rest of the path and append it to the original prefix. - self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?; + self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None, None)?; prefix.span = lo.to(self.prev_token.span); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 37b4c371c94b4..2af0caa1bdaf7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1413,7 +1413,7 @@ impl<'a> Parser<'a> { // Parse `pub(in path)`. self.bump(); // `(` self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?; // `path` + let path = self.parse_path(PathStyle::Mod, None)?; // `path` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), @@ -1430,7 +1430,7 @@ impl<'a> Parser<'a> { { // Parse `pub(crate)`, `pub(self)`, or `pub(super)`. self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` + let path = self.parse_path(PathStyle::Mod, None)?; // `crate`/`super`/`self` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), @@ -1456,7 +1456,7 @@ impl<'a> Parser<'a> { /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; + let path = self.parse_path(PathStyle::Mod, None)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` let path_str = pprust::path_to_string(&path); diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index adb0d372a40df..a09c1e4d7fde2 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -131,7 +131,7 @@ impl<'a> Parser<'a> { }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { token::NtPat(self.collect_tokens_no_attrs(|this| match kind { - NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None), + NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None), NonterminalKind::PatWithOr { .. } => this.parse_pat_allow_top_alt( None, RecoverComma::No, @@ -168,7 +168,7 @@ impl<'a> Parser<'a> { }.into_diagnostic(&self.sess.span_diagnostic)); } NonterminalKind::Path => token::NtPath( - P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?), + P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type, None))?), ), NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item(true)?)), NonterminalKind::Vis => token::NtVis( diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index e0539c4ac04dc..615ef28db085d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -80,7 +80,8 @@ enum EatOrResult { } /// The syntax location of a given pattern. Used for diagnostics. -pub(super) enum PatternLocation { +#[derive(Clone, Copy)] +pub enum PatternLocation { LetBinding, FunctionParameter, } @@ -91,8 +92,12 @@ impl<'a> Parser<'a> { /// Corresponds to `pat` in RFC 2535 and does not admit or-patterns /// at the top level. Used when parsing the parameters of lambda expressions, /// functions, function pointers, and `pat` macro fragments. - pub fn parse_pat_no_top_alt(&mut self, expected: Option) -> PResult<'a, P> { - self.parse_pat_with_range_pat(true, expected) + pub fn parse_pat_no_top_alt( + &mut self, + expected: Option, + syntax_loc: Option, + ) -> PResult<'a, P> { + self.parse_pat_with_range_pat(true, expected, syntax_loc) } /// Parses a pattern. @@ -110,7 +115,7 @@ impl<'a> Parser<'a> { ra: RecoverColon, rt: CommaRecoveryMode, ) -> PResult<'a, P> { - self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt).map(|(pat, _)| pat) + self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat) } /// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true = @@ -121,6 +126,7 @@ impl<'a> Parser<'a> { rc: RecoverComma, ra: RecoverColon, rt: CommaRecoveryMode, + syntax_loc: Option, ) -> PResult<'a, (P, bool)> { // Keep track of whether we recovered from a trailing vert so that we can avoid duplicated // suggestions (which bothers rustfix). @@ -133,7 +139,7 @@ impl<'a> Parser<'a> { }; // Parse the first pattern (`p_0`). - let mut first_pat = self.parse_pat_no_top_alt(expected)?; + let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc.clone())?; if rc == RecoverComma::Yes { self.maybe_recover_unexpected_comma(first_pat.span, rt)?; } @@ -172,7 +178,7 @@ impl<'a> Parser<'a> { break; } } - let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| { + let pat = self.parse_pat_no_top_alt(expected, syntax_loc).map_err(|mut err| { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; @@ -208,6 +214,7 @@ impl<'a> Parser<'a> { rc, RecoverColon::No, CommaRecoveryMode::LikelyTuple, + Some(syntax_loc), )?; let colon = self.eat(&token::Colon); @@ -319,6 +326,7 @@ impl<'a> Parser<'a> { &mut self, allow_range_pat: bool, expected: Option, + syntax_loc: Option, ) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole!(self, NtPat, |x| x); @@ -393,7 +401,7 @@ impl<'a> Parser<'a> { (Some(qself), path) } else { // Parse an unqualified path - (None, self.parse_path(PathStyle::Pat)?) + (None, self.parse_path(PathStyle::Pat, syntax_loc)?) }; let span = lo.to(self.prev_token.span); @@ -485,7 +493,7 @@ impl<'a> Parser<'a> { // At this point we attempt to parse `@ $pat_rhs` and emit an error. self.bump(); // `@` - let mut rhs = self.parse_pat_no_top_alt(None)?; + let mut rhs = self.parse_pat_no_top_alt(None, None)?; let whole_span = lhs.span.to(rhs.span); if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind { @@ -541,7 +549,7 @@ impl<'a> Parser<'a> { } let mutbl = self.parse_mutability(); - let subpat = self.parse_pat_with_range_pat(false, expected)?; + let subpat = self.parse_pat_with_range_pat(false, expected, None)?; Ok(PatKind::Ref(subpat, mutbl)) } @@ -584,7 +592,7 @@ impl<'a> Parser<'a> { } // Parse the pattern we hope to be an identifier. - let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier))?; + let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?; // If we don't have `mut $ident (@ pat)?`, error. if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind @@ -776,7 +784,7 @@ impl<'a> Parser<'a> { (Some(qself), path) } else { // Parse an unqualified path - (None, self.parse_path(PathStyle::Pat)?) + (None, self.parse_path(PathStyle::Pat, None)?) }; let hi = self.prev_token.span; Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path))) @@ -814,7 +822,7 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; let sub = if self.eat(&token::At) { - Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?) + Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?) } else { None }; @@ -903,14 +911,14 @@ impl<'a> Parser<'a> { // We cannot use `parse_pat_ident()` since it will complain `box` // is not an identifier. let sub = if self.eat(&token::At) { - Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?) + Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?) } else { None }; Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub)) } else { - let pat = self.parse_pat_with_range_pat(false, None)?; + let pat = self.parse_pat_with_range_pat(false, None, None)?; self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span)); Ok(PatKind::Box(pat)) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4fe8a5aa62609..0d5f48e424e2c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,3 +1,4 @@ +use super::pat::PatternLocation; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; use crate::errors::{GenericArgsInPatRequireTurbofishSyntax, PathSingleColon}; @@ -79,7 +80,7 @@ impl<'a> Parser<'a> { let (mut path, path_span); if self.eat_keyword(kw::As) { let path_lo = self.token.span; - path = self.parse_path(PathStyle::Type)?; + path = self.parse_path(PathStyle::Type, None)?; path_span = path_lo.to(self.prev_token.span); } else { path_span = self.token.span.to(self.token.span); @@ -98,7 +99,7 @@ impl<'a> Parser<'a> { } let qself = P(QSelf { ty, path_span, position: path.segments.len() }); - self.parse_path_segments(&mut path.segments, style, None)?; + self.parse_path_segments(&mut path.segments, style, None, None)?; Ok(( qself, @@ -139,8 +140,12 @@ impl<'a> Parser<'a> { true } - pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { - self.parse_path_inner(style, None) + pub(super) fn parse_path( + &mut self, + style: PathStyle, + syntax_loc: Option, + ) -> PResult<'a, Path> { + self.parse_path_inner(style, None, syntax_loc) } /// Parses simple paths. @@ -157,6 +162,7 @@ impl<'a> Parser<'a> { &mut self, style: PathStyle, ty_generics: Option<&Generics>, + syntax_loc: Option, ) -> PResult<'a, Path> { let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| { // Ensure generic arguments don't end up in attribute paths, such as: @@ -201,7 +207,7 @@ impl<'a> Parser<'a> { if self.eat(&token::ModSep) { segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); } - self.parse_path_segments(&mut segments, style, ty_generics)?; + self.parse_path_segments(&mut segments, style, ty_generics, syntax_loc)?; Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None }) } @@ -210,9 +216,10 @@ impl<'a> Parser<'a> { segments: &mut ThinVec, style: PathStyle, ty_generics: Option<&Generics>, + syntax_loc: Option, ) -> PResult<'a, ()> { loop { - let segment = self.parse_path_segment(style, ty_generics)?; + let segment = self.parse_path_segment(style, ty_generics, syntax_loc)?; if style.has_generic_ambiguity() { // In order to check for trailing angle brackets, we must have finished // recursing (`parse_path_segment` can indirectly call this function), @@ -267,6 +274,7 @@ impl<'a> Parser<'a> { &mut self, style: PathStyle, ty_generics: Option<&Generics>, + syntax_loc: Option, ) -> PResult<'a, PathSegment> { let ident = self.parse_path_segment_ident()?; let is_args_start = |token: &Token| { @@ -286,6 +294,17 @@ impl<'a> Parser<'a> { is_args_start(&this.token) }; + if let Some(PatternLocation::FunctionParameter) = syntax_loc { + } else if style == PathStyle::Pat + && self.check_noexpect(&token::Lt) + && self.look_ahead(1, |t| t.can_begin_type()) + { + return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax { + span: self.token.span, + suggest_turbofish: self.token.span.shrink_to_lo(), + })); + } + Ok( if style == PathStyle::Type && check_args_start(self) || style != PathStyle::Mod @@ -382,14 +401,6 @@ impl<'a> Parser<'a> { }; PathSegment { ident, args: Some(args), id: ast::DUMMY_NODE_ID } - } else if style == PathStyle::Pat - && self.check_noexpect(&token::Lt) - && self.look_ahead(1, |t| t.can_begin_type()) - { - return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax { - span: self.token.span, - suggest_turbofish: self.token.span.shrink_to_lo(), - })); } else { // Generic arguments are not found. PathSegment::from_ident(ident) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 9fcf51a04ec05..2c08e984be578 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> { let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let path = this.parse_path(PathStyle::Expr)?; + let path = this.parse_path(PathStyle::Expr, None)?; if this.eat(&token::Not) { let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 3bb50b05aa346..8be84c7d46224 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -289,7 +289,7 @@ impl<'a> Parser<'a> { recover_return_sign, )? } else { - let path = self.parse_path(PathStyle::Type)?; + let path = self.parse_path(PathStyle::Type, None)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)? } @@ -649,7 +649,7 @@ impl<'a> Parser<'a> { ty_generics: Option<&Generics>, ) -> PResult<'a, TyKind> { // Simple path - let path = self.parse_path_inner(PathStyle::Type, ty_generics)?; + let path = self.parse_path_inner(PathStyle::Type, ty_generics, None)?; if self.eat(&token::Not) { // Macro invocation in type position Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? }))) @@ -865,7 +865,7 @@ impl<'a> Parser<'a> { path } else { - self.parse_path(PathStyle::Type)? + self.parse_path(PathStyle::Type, None)? }; if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) { diff --git a/tests/ui/anon-params/anon-params-denied-2018.stderr b/tests/ui/anon-params/anon-params-denied-2018.stderr index bb60c898e8122..ede0e70cd7100 100644 --- a/tests/ui/anon-params/anon-params-denied-2018.stderr +++ b/tests/ui/anon-params/anon-params-denied-2018.stderr @@ -45,10 +45,14 @@ LL | fn foo_with_qualified_path(::Baz); | ^ expected one of 8 possible tokens | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: explicitly ignore the parameter name +help: if this is a `self` type, give it a parameter name + | +LL | fn foo_with_qualified_path(self: ::Baz); + | +++++ +help: if this is a type, explicitly ignore the parameter name | LL | fn foo_with_qualified_path(_: ::Baz); - | ~~~~~~~~~~~~~~~~~~ + | ++ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:15:56 @@ -69,10 +73,14 @@ LL | fn foo_with_multiple_qualified_paths(::Baz, ::Baz); | ^ expected one of 8 possible tokens | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: explicitly ignore the parameter name +help: if this is a `self` type, give it a parameter name + | +LL | fn foo_with_multiple_qualified_paths(self: ::Baz, ::Baz); + | +++++ +help: if this is a type, explicitly ignore the parameter name | LL | fn foo_with_multiple_qualified_paths(_: ::Baz, ::Baz); - | ~~~~~~~~~~~~~~~~~~ + | ++ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:18:74 @@ -81,10 +89,10 @@ LL | fn foo_with_multiple_qualified_paths(::Baz, ::Baz); | ^ expected one of 8 possible tokens | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: explicitly ignore the parameter name +help: if this is a type, explicitly ignore the parameter name | LL | fn foo_with_multiple_qualified_paths(::Baz, _: ::Baz); - | ~~~~~~~~~~~~~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:22:36 diff --git a/tests/ui/span/issue-34264.rs b/tests/ui/span/issue-34264.rs index c7a8440f28401..9227ee482dfa5 100644 --- a/tests/ui/span/issue-34264.rs +++ b/tests/ui/span/issue-34264.rs @@ -1,5 +1,5 @@ fn foo(Option, String) {} //~ ERROR expected one of -//~^ ERROR generic args in patterns require the turbofish syntax +//~^ ERROR expected one of fn bar(x, y: usize) {} //~ ERROR expected one of fn main() { diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index 1874d7f853379..8c639d5513b53 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -1,13 +1,18 @@ -error: generic args in patterns require the turbofish syntax +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `<` --> $DIR/issue-34264.rs:1:14 | LL | fn foo(Option, String) {} - | ^ + | ^ expected one of 9 possible tokens | -help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn foo(self: Option, String) {} + | +++++ +help: if this is a type, explicitly ignore the parameter name | -LL | fn foo(Option::, String) {} - | ++ +LL | fn foo(_: Option, String) {} + | ++ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 diff --git a/tests/ui/suggestions/issue-64252-self-type.rs b/tests/ui/suggestions/issue-64252-self-type.rs index ad25d334507fc..ea76dc8742b9b 100644 --- a/tests/ui/suggestions/issue-64252-self-type.rs +++ b/tests/ui/suggestions/issue-64252-self-type.rs @@ -1,12 +1,11 @@ // This test checks that a suggestion to add a `self: ` parameter name is provided // to functions where this is applicable. -pub fn foo(Box) { } //~ ERROR generic args in patterns require the turbofish syntax - +pub fn foo(Box) { } //~ ERROR expected one of struct Bar; impl Bar { - fn bar(Box) { } //~ ERROR generic args in patterns require the turbofish syntax + fn bar(Box) { } //~ ERROR expected one of } fn main() { } diff --git a/tests/ui/suggestions/issue-64252-self-type.stderr b/tests/ui/suggestions/issue-64252-self-type.stderr index ba5c2da241500..dd83d6a1cb291 100644 --- a/tests/ui/suggestions/issue-64252-self-type.stderr +++ b/tests/ui/suggestions/issue-64252-self-type.stderr @@ -1,24 +1,34 @@ -error: generic args in patterns require the turbofish syntax +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `<` --> $DIR/issue-64252-self-type.rs:4:15 | LL | pub fn foo(Box) { } - | ^ + | ^ expected one of 9 possible tokens | -help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name | -LL | pub fn foo(Box::) { } - | ++ +LL | pub fn foo(self: Box) { } + | +++++ +help: if this is a type, explicitly ignore the parameter name + | +LL | pub fn foo(_: Box) { } + | ++ -error: generic args in patterns require the turbofish syntax - --> $DIR/issue-64252-self-type.rs:9:15 +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `<` + --> $DIR/issue-64252-self-type.rs:8:15 | LL | fn bar(Box) { } - | ^ + | ^ expected one of 9 possible tokens + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name | -help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments +LL | fn bar(self: Box) { } + | +++++ +help: if this is a type, explicitly ignore the parameter name | -LL | fn bar(Box::) { } - | ++ +LL | fn bar(_: Box) { } + | ++ error: aborting due to 2 previous errors From f5243d2bfc9c8982523d443e960f8b8c54f6cd73 Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Thu, 3 Aug 2023 00:13:41 +0800 Subject: [PATCH 10/19] Fix rustfmt dep --- src/tools/rustfmt/src/parse/macros/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 67f3985926e2f..7a802f7a88e06 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -56,7 +56,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { ); parse_macro_arg!( Pat, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None), + |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None, None), |x: ptr::P| Some(x) ); // `parse_item` returns `Option>`. From 7767cbb3b0b332fd0a46e347ea7f68f20109d768 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Aug 2023 16:14:36 +0200 Subject: [PATCH 11/19] const validation: point at where we found a pointer but expected an integer --- compiler/rustc_const_eval/messages.ftl | 108 ++++++------ compiler/rustc_const_eval/src/errors.rs | 154 ++++++++++-------- .../src/interpret/validity.rs | 102 +++++++----- .../src/mir/interpret/allocation.rs | 66 +++++--- .../interpret/allocation/provenance_map.rs | 14 +- .../rustc_middle/src/mir/interpret/error.rs | 38 ++--- .../rustc_middle/src/mir/interpret/mod.rs | 10 +- .../rustc_middle/src/mir/interpret/value.rs | 9 +- src/tools/miri/src/diagnostics.rs | 4 +- .../tests/fail/validity/uninit_float.stderr | 4 +- .../tests/fail/validity/uninit_integer.stderr | 4 +- tests/ui/const-ptr/forbidden_slices.stderr | 12 +- ...inter-values-in-various-types.64bit.stderr | 54 +++--- .../consts/const-eval/raw-bytes.32bit.stderr | 19 ++- .../consts/const-eval/raw-bytes.64bit.stderr | 19 ++- .../const-eval/ref_to_int_match.32bit.stderr | 2 +- .../const-eval/ref_to_int_match.64bit.stderr | 2 +- .../ui/consts/const-eval/ub-enum.32bit.stderr | 10 +- .../ui/consts/const-eval/ub-enum.64bit.stderr | 10 +- .../const-eval/ub-int-array.32bit.stderr | 39 +++-- .../const-eval/ub-int-array.64bit.stderr | 39 +++-- tests/ui/consts/const-eval/ub-int-array.rs | 84 +++++----- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 6 +- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 12 +- .../consts/extra-const-ub/detect-extra-ub.rs | 34 +++- .../detect-extra-ub.with_flag.stderr | 34 +++- tests/ui/consts/issue-83182.rs | 9 - tests/ui/consts/issue-83182.stderr | 15 -- tests/ui/consts/issue-miri-1910.stderr | 2 +- tests/ui/consts/miri_unleashed/ptr_arith.rs | 4 +- .../ui/consts/miri_unleashed/ptr_arith.stderr | 2 +- .../intrinsics/intrinsic-raw_eq-const-bad.rs | 17 ++ ...derr => intrinsic-raw_eq-const-bad.stderr} | 10 +- .../intrinsic-raw_eq-const-padding.rs | 10 -- 34 files changed, 547 insertions(+), 411 deletions(-) delete mode 100644 tests/ui/consts/issue-83182.rs delete mode 100644 tests/ui/consts/issue-83182.stderr create mode 100644 tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs rename tests/ui/intrinsics/{intrinsic-raw_eq-const-padding.stderr => intrinsic-raw_eq-const-bad.stderr} (54%) delete mode 100644 tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2905874eec5f1..0b336109921fe 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -15,9 +15,6 @@ const_eval_await_non_const = cannot convert `{$ty}` into a future in {const_eval_const_context}s const_eval_bounds_check_failed = indexing out of bounds: the len is {$len} but the index is {$index} -const_eval_box_to_mut = {$front_matter}: encountered a box pointing to mutable memory in a constant -const_eval_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant -const_eval_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty} const_eval_call_nonzero_intrinsic = `{$name}` called on 0 @@ -41,18 +38,12 @@ const_eval_const_context = {$kind -> const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges -const_eval_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance) -const_eval_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation) -const_eval_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free) const_eval_dangling_int_pointer = {$bad_pointer_message}: {$pointer} is a dangling pointer (it has no provenance) const_eval_dangling_null_pointer = {$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance) const_eval_dangling_ptr_in_final = encountered dangling pointer in final constant -const_eval_dangling_ref_no_provenance = {$front_matter}: encountered a dangling reference ({$pointer} has no provenance) -const_eval_dangling_ref_out_of_bounds = {$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation) -const_eval_dangling_ref_use_after_free = {$front_matter}: encountered a dangling reference (use-after-free) const_eval_dead_local = accessing a dead local variable const_eval_dealloc_immutable = @@ -105,7 +96,6 @@ const_eval_error = {$error_kind -> const_eval_exact_div_has_remainder = exact_div: {$a} cannot be divided by {$b} without remainder -const_eval_expected_non_ptr = {$front_matter}: encountered `{$value}`, but expected plain (non-pointer) bytes const_eval_fn_ptr_call = function pointers need an RFC before allowed to be called in {const_eval_const_context}s const_eval_for_loop_into_iter_non_const = @@ -156,8 +146,6 @@ const_eval_invalid_align_details = const_eval_invalid_bool = interpreting an invalid 8-bit value as a bool: 0x{$value} -const_eval_invalid_box_meta = {$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object -const_eval_invalid_box_slice_meta = {$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object const_eval_invalid_char = interpreting an invalid 32-bit value as a char: 0x{$value} const_eval_invalid_dealloc = @@ -168,16 +156,12 @@ const_eval_invalid_dealloc = *[other] {""} } -const_eval_invalid_enum_tag = {$front_matter}: encountered {$value}, but expected a valid enum tag -const_eval_invalid_fn_ptr = {$front_matter}: encountered {$value}, but expected a function pointer const_eval_invalid_function_pointer = using {$pointer} as function pointer but it does not point to a function const_eval_invalid_meta = invalid metadata in wide pointer: total size is bigger than largest supported object const_eval_invalid_meta_slice = invalid metadata in wide pointer: slice is bigger than largest supported object -const_eval_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object -const_eval_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object const_eval_invalid_str = this string is not valid UTF-8: {$err} const_eval_invalid_tag = @@ -189,14 +173,10 @@ const_eval_invalid_uninit_bytes = reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory const_eval_invalid_uninit_bytes_unknown = using uninitialized data, but this operation requires initialized memory -const_eval_invalid_value = constructing invalid value -const_eval_invalid_value_with_path = constructing invalid value at {$path} -## The `front_matter`s here refer to either `middle_invalid_value` or `middle_invalid_value_with_path`. const_eval_invalid_vtable_pointer = using {$pointer} as vtable pointer but it does not point to a vtable -const_eval_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer const_eval_live_drop = destructor of `{$dropped_ty}` cannot be evaluated at compile-time @@ -218,14 +198,13 @@ const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant const_eval_memory_access_test = memory access failed const_eval_memory_exhausted = tried to allocate more memory than available to compiler + const_eval_modified_global = modifying a static's initial value from another static's initializer const_eval_mut_deref = mutation through a reference is not allowed in {const_eval_const_context}s -const_eval_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const` -const_eval_never_val = {$front_matter}: encountered a value of the never type `!` const_eval_non_const_fmt_macro_call = cannot call non-const formatting macro in {const_eval_const_context}s @@ -241,10 +220,6 @@ const_eval_noreturn_asm_returned = const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires -const_eval_null_box = {$front_matter}: encountered a null box -const_eval_null_fn_ptr = {$front_matter}: encountered a null function pointer -const_eval_null_ref = {$front_matter}: encountered a null reference -const_eval_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range} const_eval_nullary_intrinsic_fail = could not evaluate nullary intrinsic @@ -257,7 +232,6 @@ const_eval_offset_from_underflow = const_eval_operator_non_const = cannot call non-const operator in {const_eval_const_context}s -const_eval_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range} const_eval_overflow = overflow executing `{$name}` @@ -287,7 +261,6 @@ const_eval_ptr_as_bytes_1 = this code performed an operation that depends on the underlying bytes representing a pointer const_eval_ptr_as_bytes_2 = the absolute address of a pointer is not known at compile-time, so such operations are not supported -const_eval_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range} const_eval_question_branch_non_const = `?` cannot determine the branch of `{$ty}` in {const_eval_const_context}s @@ -315,8 +288,8 @@ const_eval_raw_ptr_to_int = const_eval_read_extern_static = cannot read from extern static ({$did}) -const_eval_read_pointer_as_bytes = - unable to turn pointer into raw bytes +const_eval_read_pointer_as_int = + unable to turn pointer into integer const_eval_realloc_or_alloc_with_offset = {$kind -> [dealloc] deallocating @@ -324,9 +297,6 @@ const_eval_realloc_or_alloc_with_offset = *[other] {""} } {$ptr} which does not point to the beginning of an object -const_eval_ref_to_mut = {$front_matter}: encountered a reference pointing to mutable memory in a constant -const_eval_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant -const_eval_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} const_eval_remainder_by_zero = calculating the remainder with a divisor of zero const_eval_remainder_overflow = @@ -363,8 +333,6 @@ const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in const_eval_try_block_from_output_non_const = `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s -const_eval_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) -const_eval_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes}) const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s const_eval_unallowed_heap_allocations = @@ -408,29 +376,14 @@ const_eval_undefined_behavior = const_eval_undefined_behavior_note = The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -const_eval_uninhabited_enum_tag = {$front_matter}: encountered an uninhabited enum variant const_eval_uninhabited_enum_variant_read = read discriminant of an uninhabited enum variant const_eval_uninhabited_enum_variant_written = writing discriminant of an uninhabited enum variant -const_eval_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}` -const_eval_uninit = {$front_matter}: encountered uninitialized bytes -const_eval_uninit_bool = {$front_matter}: encountered uninitialized memory, but expected a boolean -const_eval_uninit_box = {$front_matter}: encountered uninitialized memory, but expected a box -const_eval_uninit_char = {$front_matter}: encountered uninitialized memory, but expected a unicode scalar value -const_eval_uninit_enum_tag = {$front_matter}: encountered uninitialized bytes, but expected a valid enum tag -const_eval_uninit_float = {$front_matter}: encountered uninitialized memory, but expected a floating point number -const_eval_uninit_fn_ptr = {$front_matter}: encountered uninitialized memory, but expected a function pointer -const_eval_uninit_init_scalar = {$front_matter}: encountered uninitialized memory, but expected initialized scalar value -const_eval_uninit_int = {$front_matter}: encountered uninitialized memory, but expected an integer -const_eval_uninit_raw_ptr = {$front_matter}: encountered uninitialized memory, but expected a raw pointer -const_eval_uninit_ref = {$front_matter}: encountered uninitialized memory, but expected a reference -const_eval_uninit_str = {$front_matter}: encountered uninitialized data in `str` const_eval_unreachable = entering unreachable code const_eval_unreachable_unwind = unwinding past a stack frame that does not allow unwinding -const_eval_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const` const_eval_unsigned_offset_from_overflow = `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset} @@ -453,8 +406,63 @@ const_eval_unwind_past_top = const_eval_upcast_mismatch = upcast on a pointer whose vtable does not match its type +## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`. +## (We'd love to sort this differently to make that more clear but tidy won't let us...) +const_eval_validation_box_to_mut = {$front_matter}: encountered a box pointing to mutable memory in a constant +const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant +const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty} +const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance) +const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation) +const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free) +const_eval_validation_dangling_ref_no_provenance = {$front_matter}: encountered a dangling reference ({$pointer} has no provenance) +const_eval_validation_dangling_ref_out_of_bounds = {$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation) +const_eval_validation_dangling_ref_use_after_free = {$front_matter}: encountered a dangling reference (use-after-free) + +const_eval_validation_expected_bool = expected a boolean +const_eval_validation_expected_box = expected a box +const_eval_validation_expected_char = expected a unicode scalar value +const_eval_validation_expected_enum_tag = expected a valid enum tag +const_eval_validation_expected_float = expected a floating point number +const_eval_validation_expected_fn_ptr = expected a function pointer +const_eval_validation_expected_init_scalar = expected initialized scalar value +const_eval_validation_expected_int = expected an integer +const_eval_validation_expected_raw_ptr = expected a raw pointer +const_eval_validation_expected_ref = expected a reference +const_eval_validation_expected_str = expected a string + +const_eval_validation_front_matter_invalid_value = constructing invalid value +const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path} + const_eval_validation_invalid_bool = {$front_matter}: encountered {$value}, but expected a boolean +const_eval_validation_invalid_box_meta = {$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object +const_eval_validation_invalid_box_slice_meta = {$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object const_eval_validation_invalid_char = {$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + +const_eval_validation_invalid_enum_tag = {$front_matter}: encountered {$value}, but expected a valid enum tag +const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, but expected a function pointer +const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object +const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object +const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer +const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const` +const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` +const_eval_validation_null_box = {$front_matter}: encountered a null box +const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer +const_eval_validation_null_ref = {$front_matter}: encountered a null reference +const_eval_validation_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range} +const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range} +const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers +const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} +const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range} +const_eval_validation_ref_to_mut = {$front_matter}: encountered a reference pointing to mutable memory in a constant +const_eval_validation_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant +const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} +const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) +const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes}) +const_eval_validation_uninhabited_enum_variant = {$front_matter}: encountered an uninhabited enum variant +const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}` +const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected} +const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const` + const_eval_write_to_read_only = writing to {$allocation} which is read-only const_eval_zst_pointer_out_of_bounds = diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 8cbc68d906140..3a4e2648b808e 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -513,7 +513,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch, UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written, UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read, - Validation(e) => e.diagnostic_message(), + ValidationError(e) => e.diagnostic_message(), Custom(x) => (x.msg)(), } } @@ -587,13 +587,13 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { InvalidUninitBytes(Some((alloc, info))) => { builder.set_arg("alloc", alloc); builder.set_arg("access", info.access); - builder.set_arg("uninit", info.uninit); + builder.set_arg("uninit", info.bad); } ScalarSizeMismatch(info) => { builder.set_arg("target_size", info.target_size); builder.set_arg("data_size", info.data_size); } - Validation(e) => e.add_args(handler, builder), + ValidationError(e) => e.add_args(handler, builder), Custom(custom) => { (custom.add_args)(&mut |name, value| { builder.set_arg(name, value); @@ -608,74 +608,72 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { use crate::fluent_generated::*; use rustc_middle::mir::interpret::ValidationErrorKind::*; match self.kind { - PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => const_eval_box_to_uninhabited, - PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => const_eval_ref_to_uninhabited, - - PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_box_to_static, - PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_ref_to_static, - - PtrToMut { ptr_kind: PointerKind::Box } => const_eval_box_to_mut, - PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_ref_to_mut, - - ExpectedNonPtr { .. } => const_eval_expected_non_ptr, - MutableRefInConst => const_eval_mutable_ref_in_const, - NullFnPtr => const_eval_null_fn_ptr, - NeverVal => const_eval_never_val, - NullablePtrOutOfRange { .. } => const_eval_nullable_ptr_out_of_range, - PtrOutOfRange { .. } => const_eval_ptr_out_of_range, - OutOfRange { .. } => const_eval_out_of_range, - UnsafeCell => const_eval_unsafe_cell, - UninhabitedVal { .. } => const_eval_uninhabited_val, - InvalidEnumTag { .. } => const_eval_invalid_enum_tag, - UninhabitedEnumTag => const_eval_uninhabited_enum_tag, - UninitEnumTag => const_eval_uninit_enum_tag, - UninitStr => const_eval_uninit_str, - Uninit { expected: ExpectedKind::Bool } => const_eval_uninit_bool, - Uninit { expected: ExpectedKind::Reference } => const_eval_uninit_ref, - Uninit { expected: ExpectedKind::Box } => const_eval_uninit_box, - Uninit { expected: ExpectedKind::RawPtr } => const_eval_uninit_raw_ptr, - Uninit { expected: ExpectedKind::InitScalar } => const_eval_uninit_init_scalar, - Uninit { expected: ExpectedKind::Char } => const_eval_uninit_char, - Uninit { expected: ExpectedKind::Float } => const_eval_uninit_float, - Uninit { expected: ExpectedKind::Int } => const_eval_uninit_int, - Uninit { expected: ExpectedKind::FnPtr } => const_eval_uninit_fn_ptr, - UninitVal => const_eval_uninit, - InvalidVTablePtr { .. } => const_eval_invalid_vtable_ptr, + PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => { + const_eval_validation_box_to_uninhabited + } + PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => { + const_eval_validation_ref_to_uninhabited + } + + PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static, + PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_static, + + PtrToMut { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_mut, + PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_mut, + + PointerAsInt { .. } => const_eval_validation_pointer_as_int, + PartialPointer => const_eval_validation_partial_pointer, + MutableRefInConst => const_eval_validation_mutable_ref_in_const, + NullFnPtr => const_eval_validation_null_fn_ptr, + NeverVal => const_eval_validation_never_val, + NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range, + PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range, + OutOfRange { .. } => const_eval_validation_out_of_range, + UnsafeCell => const_eval_validation_unsafe_cell, + UninhabitedVal { .. } => const_eval_validation_uninhabited_val, + InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag, + UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant, + Uninit { .. } => const_eval_validation_uninit, + InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr, InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => { - const_eval_invalid_box_slice_meta + const_eval_validation_invalid_box_slice_meta } InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref } => { - const_eval_invalid_ref_slice_meta + const_eval_validation_invalid_ref_slice_meta } - InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => const_eval_invalid_box_meta, - InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => const_eval_invalid_ref_meta, - UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_unaligned_ref, - UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_unaligned_box, + InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => { + const_eval_validation_invalid_box_meta + } + InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => { + const_eval_validation_invalid_ref_meta + } + UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_validation_unaligned_ref, + UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box, - NullPtr { ptr_kind: PointerKind::Box } => const_eval_null_box, - NullPtr { ptr_kind: PointerKind::Ref } => const_eval_null_ref, + NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box, + NullPtr { ptr_kind: PointerKind::Ref } => const_eval_validation_null_ref, DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => { - const_eval_dangling_box_no_provenance + const_eval_validation_dangling_box_no_provenance } DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref, .. } => { - const_eval_dangling_ref_no_provenance + const_eval_validation_dangling_ref_no_provenance } DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => { - const_eval_dangling_box_out_of_bounds + const_eval_validation_dangling_box_out_of_bounds } DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref } => { - const_eval_dangling_ref_out_of_bounds + const_eval_validation_dangling_ref_out_of_bounds } DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => { - const_eval_dangling_box_use_after_free + const_eval_validation_dangling_box_use_after_free } DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref } => { - const_eval_dangling_ref_use_after_free + const_eval_validation_dangling_ref_use_after_free } InvalidBool { .. } => const_eval_validation_invalid_bool, InvalidChar { .. } => const_eval_validation_invalid_char, - InvalidFnPtr { .. } => const_eval_invalid_fn_ptr, + InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr, } } @@ -683,13 +681,21 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { use crate::fluent_generated as fluent; use rustc_middle::mir::interpret::ValidationErrorKind::*; + if let PointerAsInt { .. } | PartialPointer = self.kind { + err.help(fluent::const_eval_ptr_as_bytes_1); + err.help(fluent::const_eval_ptr_as_bytes_2); + } + let message = if let Some(path) = self.path { handler.eagerly_translate_to_string( - fluent::const_eval_invalid_value_with_path, + fluent::const_eval_validation_front_matter_invalid_value_with_path, [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)), ) } else { - handler.eagerly_translate_to_string(fluent::const_eval_invalid_value, [].into_iter()) + handler.eagerly_translate_to_string( + fluent::const_eval_validation_front_matter_invalid_value, + [].into_iter(), + ) }; err.set_arg("front_matter", message); @@ -729,8 +735,24 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => { err.set_arg("ty", ty); } - ExpectedNonPtr { value } - | InvalidEnumTag { value } + PointerAsInt { expected } | Uninit { expected } => { + let msg = match expected { + ExpectedKind::Reference => fluent::const_eval_validation_expected_ref, + ExpectedKind::Box => fluent::const_eval_validation_expected_box, + ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr, + ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar, + ExpectedKind::Bool => fluent::const_eval_validation_expected_bool, + ExpectedKind::Char => fluent::const_eval_validation_expected_char, + ExpectedKind::Float => fluent::const_eval_validation_expected_float, + ExpectedKind::Int => fluent::const_eval_validation_expected_int, + ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr, + ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag, + ExpectedKind::Str => fluent::const_eval_validation_expected_str, + }; + let msg = handler.eagerly_translate_to_string(msg, [].into_iter()); + err.set_arg("expected", msg); + } + InvalidEnumTag { value } | InvalidVTablePtr { value } | InvalidBool { value } | InvalidChar { value } @@ -758,15 +780,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { | NullFnPtr | NeverVal | UnsafeCell - | UninitEnumTag - | UninitStr - | Uninit { .. } - | UninitVal | InvalidMetaSliceTooLarge { .. } | InvalidMetaTooLarge { .. } | DanglingPtrUseAfterFree { .. } | DanglingPtrOutOfBounds { .. } - | UninhabitedEnumTag => {} + | UninhabitedEnumVariant + | PartialPointer => {} } } } @@ -776,9 +795,9 @@ impl ReportErrorExt for UnsupportedOpInfo { use crate::fluent_generated::*; match self { UnsupportedOpInfo::Unsupported(s) => s.clone().into(), - UnsupportedOpInfo::PartialPointerOverwrite(_) => const_eval_partial_pointer_overwrite, - UnsupportedOpInfo::PartialPointerCopy(_) => const_eval_partial_pointer_copy, - UnsupportedOpInfo::ReadPointerAsBytes => const_eval_read_pointer_as_bytes, + UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite, + UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy, + UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int, UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static, UnsupportedOpInfo::ReadExternStatic(_) => const_eval_read_extern_static, } @@ -787,13 +806,16 @@ impl ReportErrorExt for UnsupportedOpInfo { use crate::fluent_generated::*; use UnsupportedOpInfo::*; - if let ReadPointerAsBytes | PartialPointerOverwrite(_) | PartialPointerCopy(_) = self { + if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self { builder.help(const_eval_ptr_as_bytes_1); builder.help(const_eval_ptr_as_bytes_2); } match self { - Unsupported(_) | ReadPointerAsBytes => {} - PartialPointerOverwrite(ptr) | PartialPointerCopy(ptr) => { + // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to + // be further processed by validity checking which then turns it into something nice to + // print. So it's not worth the effort of having diagnostics that can print the `info`. + Unsupported(_) | ReadPointerAsInt(_) => {} + OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { builder.set_arg("ptr", ptr); } ThreadLocalStatic(did) | ReadExternStatic(did) => { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index ff22d3d2d5abf..d3f05af1c72c3 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -25,13 +25,17 @@ use rustc_target::abi::{ use std::hash::Hash; -// for the validation errors -use super::UndefinedBehaviorInfo::*; use super::{ AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, ValueVisitor, }; +// for the validation errors +use super::InterpError::UndefinedBehavior as Ub; +use super::InterpError::Unsupported as Unsup; +use super::UndefinedBehaviorInfo::*; +use super::UnsupportedOpInfo::*; + macro_rules! throw_validation_failure { ($where:expr, $kind: expr) => {{ let where_ = &$where; @@ -43,7 +47,7 @@ macro_rules! throw_validation_failure { None }; - throw_ub!(Validation(ValidationErrorInfo { path, kind: $kind })) + throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) }}; } @@ -85,16 +89,16 @@ macro_rules! try_validation { Ok(x) => x, // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. - Err(e) => match e.into_parts() { + Err(e) => match e.kind() { $( - (InterpError::UndefinedBehavior($($p)|+), _) => + $($p)|+ => throw_validation_failure!( $where, $kind ) ),+, #[allow(unreachable_patterns)] - (e, rest) => Err::($crate::interpret::InterpErrorInfo::from_parts(e, rest))?, + _ => Err::(e)?, } } }}; @@ -294,7 +298,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(try_validation!( self.ecx.read_immediate(op), self.path, - InvalidUninitBytes(None) => Uninit { expected } + Ub(InvalidUninitBytes(None)) => + Uninit { expected }, + // The `Unsup` cases can only occur during CTFE + Unsup(ReadPointerAsInt(_)) => + PointerAsInt { expected }, + Unsup(ReadPartialPointer(_)) => + PartialPointer, )) } @@ -319,8 +329,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let (_ty, _trait) = try_validation!( self.ecx.get_ptr_vtable(vtable), self.path, - DanglingIntPointer(..) | - InvalidVTablePointer(..) => InvalidVTablePtr { value: format!("{vtable}") } + Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) => + InvalidVTablePtr { value: format!("{vtable}") } ); // FIXME: check if the type/trait match what ty::Dynamic says? } @@ -356,7 +366,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let size_and_align = try_validation!( self.ecx.size_and_align_of_mplace(&place), self.path, - InvalidMeta(msg) => match msg { + Ub(InvalidMeta(msg)) => match msg { InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind }, InvalidMetaKind::TooBig => InvalidMetaTooLarge { ptr_kind }, } @@ -375,23 +385,23 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message ), self.path, - AlignmentCheckFailed { required, has } => UnalignedPtr { + Ub(AlignmentCheckFailed { required, has }) => UnalignedPtr { ptr_kind, required_bytes: required.bytes(), found_bytes: has.bytes() }, - DanglingIntPointer(0, _) => NullPtr { ptr_kind }, - DanglingIntPointer(i, _) => DanglingPtrNoProvenance { + Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind }, + Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate - pointer: format!("{}", Pointer::>::from_addr_invalid(i)) + pointer: format!("{}", Pointer::>::from_addr_invalid(*i)) }, - PointerOutOfBounds { .. } => DanglingPtrOutOfBounds { + Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { ptr_kind }, // This cannot happen during const-eval (because interning already detects // dangling pointers), but it can happen in Miri. - PointerUseAfterFree(..) => DanglingPtrUseAfterFree { + Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree { ptr_kind, }, ); @@ -477,7 +487,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' try_validation!( value.to_bool(), self.path, - InvalidBool(..) => ValidationErrorKind::InvalidBool { + Ub(InvalidBool(..)) => ValidationErrorKind::InvalidBool { value: format!("{value:x}"), } ); @@ -488,7 +498,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' try_validation!( value.to_char(), self.path, - InvalidChar(..) => ValidationErrorKind::InvalidChar { + Ub(InvalidChar(..)) => ValidationErrorKind::InvalidChar { value: format!("{value:x}"), } ); @@ -497,7 +507,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ty::Float(_) | ty::Int(_) | ty::Uint(_) => { // NOTE: Keep this in sync with the array optimization for int/float // types below! - let value = self.read_scalar( + self.read_scalar( value, if matches!(ty.kind(), ty::Float(..)) { ExpectedKind::Float @@ -505,14 +515,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ExpectedKind::Int }, )?; - // As a special exception we *do* match on a `Scalar` here, since we truly want - // to know its underlying representation (and *not* cast it to an integer). - if matches!(value, Scalar::Ptr(..)) { - throw_validation_failure!( - self.path, - ExpectedNonPtr { value: format!("{value:x}") } - ) - } Ok(true) } ty::RawPtr(..) => { @@ -546,10 +548,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, - DanglingIntPointer(..) | - InvalidFunctionPointer(..) => InvalidFnPtr { - value: format!("{ptr}"), - }, + Ub(DanglingIntPointer(..) | InvalidFunctionPointer(..)) => + InvalidFnPtr { value: format!("{ptr}") }, ); // FIXME: Check if the signature matches } else { @@ -657,11 +657,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Ok(try_validation!( this.ecx.read_discriminant(op), this.path, - InvalidTag(val) => InvalidEnumTag { + Ub(InvalidTag(val)) => InvalidEnumTag { value: format!("{val:x}"), }, - UninhabitedEnumVariantRead(_) => UninhabitedEnumTag, - InvalidUninitBytes(None) => UninitEnumTag, + Ub(UninhabitedEnumVariantRead(_)) => UninhabitedEnumVariant, + // Uninit / bad provenance are not possible since the field was already previously + // checked at its integer type. )) }) } @@ -740,7 +741,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> try_validation!( self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len)), self.path, - InvalidUninitBytes(..) => { UninitStr }, + Ub(InvalidUninitBytes(..)) => Uninit { expected: ExpectedKind::Str }, + Unsup(ReadPointerAsInt(_)) => PointerAsInt { expected: ExpectedKind::Str } ); } ty::Array(tys, ..) | ty::Slice(tys) @@ -752,6 +754,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> if matches!(tys.kind(), ty::Int(..) | ty::Uint(..) | ty::Float(..)) => { + let expected = if tys.is_integral() { ExpectedKind::Int } else { ExpectedKind::Float }; // Optimized handling for arrays of integer/float type. // This is the length of the array/slice. @@ -770,7 +773,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Left(mplace) => mplace, Right(imm) => match *imm { Immediate::Uninit => - throw_validation_failure!(self.path, UninitVal), + throw_validation_failure!(self.path, Uninit { expected }), Immediate::Scalar(..) | Immediate::ScalarPair(..) => bug!("arrays/slices can never have Scalar/ScalarPair layout"), } @@ -796,17 +799,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // For some errors we might be able to provide extra information. // (This custom logic does not fit the `try_validation!` macro.) match err.kind() { - err_ub!(InvalidUninitBytes(Some((_alloc_id, access)))) => { + Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { // Some byte was uninitialized, determine which // element that byte belongs to so we can // provide an index. let i = usize::try_from( - access.uninit.start.bytes() / layout.size.bytes(), + access.bad.start.bytes() / layout.size.bytes(), ) .unwrap(); self.path.push(PathElem::ArrayElem(i)); - throw_validation_failure!(self.path, UninitVal) + if matches!(err.kind(), Ub(InvalidUninitBytes(_))) { + throw_validation_failure!(self.path, Uninit { expected }) + } else { + throw_validation_failure!(self.path, PointerAsInt { expected }) + } } // Propagate upwards (that will also check for unexpected errors). @@ -892,17 +899,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Run it. match visitor.visit_value(&op) { Ok(()) => Ok(()), - // Pass through validation failures. - Err(err) if matches!(err.kind(), err_ub!(Validation { .. })) => Err(err), - // Complain about any other kind of UB error -- those are bad because we'd like to + // Pass through validation failures and "invalid program" issues. + Err(err) + if matches!( + err.kind(), + err_ub!(ValidationError { .. }) | InterpError::InvalidProgram(_) + ) => + { + Err(err) + } + // Complain about any other kind of error -- those are bad because we'd like to // report them in a way that shows *where* in the value the issue lies. - Err(err) if matches!(err.kind(), InterpError::UndefinedBehavior(_)) => { + Err(err) => { let (err, backtrace) = err.into_parts(); backtrace.print_backtrace(); bug!("Unexpected Undefined Behavior error during validation: {err:?}"); } - // Pass through everything else. - Err(err) => Err(err), } } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index c1cb2f2e497f4..2567170f39afe 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -18,9 +18,9 @@ use rustc_span::DUMMY_SP; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ - read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance, - ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, - UnsupportedOpInfo, + read_target_uint, write_target_uint, AllocId, BadBytesAccess, InterpError, InterpResult, + Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, + UndefinedBehaviorInfo, UnsupportedOpInfo, }; use crate::ty; use init_mask::*; @@ -173,13 +173,13 @@ pub enum AllocError { /// A scalar had the wrong size. ScalarSizeMismatch(ScalarSizeMismatch), /// Encountered a pointer where we needed raw bytes. - ReadPointerAsBytes, + ReadPointerAsInt(Option), /// Partially overwriting a pointer. - PartialPointerOverwrite(Size), + OverwritePartialPointer(Size), /// Partially copying a pointer. - PartialPointerCopy(Size), + ReadPartialPointer(Size), /// Using uninitialized data where it is not allowed. - InvalidUninitBytes(Option), + InvalidUninitBytes(Option), } pub type AllocResult = Result; @@ -196,12 +196,14 @@ impl AllocError { ScalarSizeMismatch(s) => { InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s)) } - ReadPointerAsBytes => InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes), - PartialPointerOverwrite(offset) => InterpError::Unsupported( - UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)), + ReadPointerAsInt(info) => InterpError::Unsupported( + UnsupportedOpInfo::ReadPointerAsInt(info.map(|b| (alloc_id, b))), ), - PartialPointerCopy(offset) => InterpError::Unsupported( - UnsupportedOpInfo::PartialPointerCopy(Pointer::new(alloc_id, offset)), + OverwritePartialPointer(offset) => InterpError::Unsupported( + UnsupportedOpInfo::OverwritePartialPointer(Pointer::new(alloc_id, offset)), + ), + ReadPartialPointer(offset) => InterpError::Unsupported( + UnsupportedOpInfo::ReadPartialPointer(Pointer::new(alloc_id, offset)), ), InvalidUninitBytes(info) => InterpError::UndefinedBehavior( UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))), @@ -433,14 +435,26 @@ impl Allocation range: AllocRange, ) -> AllocResult<&[u8]> { self.init_mask.is_range_initialized(range).map_err(|uninit_range| { - AllocError::InvalidUninitBytes(Some(UninitBytesAccess { + AllocError::InvalidUninitBytes(Some(BadBytesAccess { access: range, - uninit: uninit_range, + bad: uninit_range, })) })?; if !Prov::OFFSET_IS_ADDR { if !self.provenance.range_empty(range, cx) { - return Err(AllocError::ReadPointerAsBytes); + // Find the provenance. + let (offset, _prov) = self + .provenance + .range_get_ptrs(range, cx) + .first() + .copied() + .expect("there must be provenance somewhere here"); + let start = offset.max(range.start); // the pointer might begin before `range`! + let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`! + return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess { + access: range, + bad: AllocRange::from(start..end), + }))); } } Ok(self.get_bytes_unchecked(range)) @@ -536,23 +550,25 @@ impl Allocation // Now use this provenance. let ptr = Pointer::new(prov, Size::from_bytes(bits)); return Ok(Scalar::from_maybe_pointer(ptr, cx)); + } else { + // Without OFFSET_IS_ADDR, the only remaining case we can handle is total absence of + // provenance. + if self.provenance.range_empty(range, cx) { + return Ok(Scalar::from_uint(bits, range.size)); + } + // Else we have mixed provenance, that doesn't work. + return Err(AllocError::ReadPartialPointer(range.start)); } } else { // We are *not* reading a pointer. - // If we can just ignore provenance, do exactly that. - if Prov::OFFSET_IS_ADDR { + // If we can just ignore provenance or there is none, that's easy. + if Prov::OFFSET_IS_ADDR || self.provenance.range_empty(range, cx) { // We just strip provenance. return Ok(Scalar::from_uint(bits, range.size)); } + // There is some provenance and we don't have OFFSET_IS_ADDR. This doesn't work. + return Err(AllocError::ReadPointerAsInt(None)); } - - // Fallback path for when we cannot treat provenance bytewise or ignore it. - assert!(!Prov::OFFSET_IS_ADDR); - if !self.provenance.range_empty(range, cx) { - return Err(AllocError::ReadPointerAsBytes); - } - // There is no provenance, we can just return the bits. - Ok(Scalar::from_uint(bits, range.size)) } /// Writes a *non-ZST* scalar. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 318f93e12b582..0243fc4513aa6 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -66,7 +66,11 @@ impl ProvenanceMap { /// Returns all ptr-sized provenance in the given range. /// If the range has length 0, returns provenance that crosses the edge between `start-1` and /// `start`. - fn range_get_ptrs(&self, range: AllocRange, cx: &impl HasDataLayout) -> &[(Size, Prov)] { + pub(super) fn range_get_ptrs( + &self, + range: AllocRange, + cx: &impl HasDataLayout, + ) -> &[(Size, Prov)] { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let adjusted_start = Size::from_bytes( @@ -158,7 +162,7 @@ impl ProvenanceMap { if first < start { if !Prov::OFFSET_IS_ADDR { // We can't split up the provenance into less than a pointer. - return Err(AllocError::PartialPointerOverwrite(first)); + return Err(AllocError::OverwritePartialPointer(first)); } // Insert the remaining part in the bytewise provenance. let prov = self.ptrs[&first]; @@ -171,7 +175,7 @@ impl ProvenanceMap { let begin_of_last = last - cx.data_layout().pointer_size; if !Prov::OFFSET_IS_ADDR { // We can't split up the provenance into less than a pointer. - return Err(AllocError::PartialPointerOverwrite(begin_of_last)); + return Err(AllocError::OverwritePartialPointer(begin_of_last)); } // Insert the remaining part in the bytewise provenance. let prov = self.ptrs[&begin_of_last]; @@ -246,10 +250,10 @@ impl ProvenanceMap { if !Prov::OFFSET_IS_ADDR { // There can't be any bytewise provenance, and we cannot split up the begin/end overlap. if let Some(entry) = begin_overlap { - return Err(AllocError::PartialPointerCopy(entry.0)); + return Err(AllocError::ReadPartialPointer(entry.0)); } if let Some(entry) = end_overlap { - return Err(AllocError::PartialPointerCopy(entry.0)); + return Err(AllocError::ReadPartialPointer(entry.0)); } debug_assert!(self.bytes.is_none()); } else { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index eaa6c0ce2d672..231ea56e49f95 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -134,10 +134,6 @@ impl InterpErrorBacktrace { } impl<'tcx> InterpErrorInfo<'tcx> { - pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self { - Self(Box::new(InterpErrorInfoInner { kind, backtrace })) - } - pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) { let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self; (kind, backtrace) @@ -226,13 +222,13 @@ impl IntoDiagnosticArg for InvalidMetaKind { } } -/// Details of an access to uninitialized bytes where it is not allowed. +/// Details of an access to uninitialized bytes / bad pointer bytes where it is not allowed. #[derive(Debug, Clone, Copy)] -pub struct UninitBytesAccess { +pub struct BadBytesAccess { /// Range of the original memory access. pub access: AllocRange, - /// Range of the uninit memory that was encountered. (Might not be maximal.) - pub uninit: AllocRange, + /// Range of the bad memory that was encountered. (Might not be maximal.) + pub bad: AllocRange, } /// Information about a size mismatch. @@ -316,7 +312,7 @@ pub enum UndefinedBehaviorInfo<'a> { /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. - InvalidUninitBytes(Option<(AllocId, UninitBytesAccess)>), + InvalidUninitBytes(Option<(AllocId, BadBytesAccess)>), /// Working with a local that is not currently live. DeadLocal, /// Data size is not equal to target size. @@ -326,7 +322,7 @@ pub enum UndefinedBehaviorInfo<'a> { /// An uninhabited enum variant is projected. UninhabitedEnumVariantRead(VariantIdx), /// Validation error. - Validation(ValidationErrorInfo<'a>), + ValidationError(ValidationErrorInfo<'a>), // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically // dispatched /// A custom (free-form) error, created by `err_ub_custom!`. @@ -368,6 +364,8 @@ pub enum ExpectedKind { Float, Int, FnPtr, + EnumTag, + Str, } impl From for ExpectedKind { @@ -381,10 +379,11 @@ impl From for ExpectedKind { #[derive(Debug)] pub enum ValidationErrorKind<'tcx> { + PointerAsInt { expected: ExpectedKind }, + PartialPointer, PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> }, PtrToStatic { ptr_kind: PointerKind }, PtrToMut { ptr_kind: PointerKind }, - ExpectedNonPtr { value: String }, MutableRefInConst, NullFnPtr, NeverVal, @@ -394,11 +393,8 @@ pub enum ValidationErrorKind<'tcx> { UnsafeCell, UninhabitedVal { ty: Ty<'tcx> }, InvalidEnumTag { value: String }, - UninhabitedEnumTag, - UninitEnumTag, - UninitStr, + UninhabitedEnumVariant, Uninit { expected: ExpectedKind }, - UninitVal, InvalidVTablePtr { value: String }, InvalidMetaSliceTooLarge { ptr_kind: PointerKind }, InvalidMetaTooLarge { ptr_kind: PointerKind }, @@ -426,12 +422,12 @@ pub enum UnsupportedOpInfo { // /// Overwriting parts of a pointer; without knowing absolute addresses, the resulting state /// cannot be represented by the CTFE interpreter. - PartialPointerOverwrite(Pointer), - /// Attempting to `copy` parts of a pointer to somewhere else; without knowing absolute + OverwritePartialPointer(Pointer), + /// Attempting to read or copy parts of a pointer to somewhere else; without knowing absolute /// addresses, the resulting state cannot be represented by the CTFE interpreter. - PartialPointerCopy(Pointer), - /// Encountered a pointer where we needed raw bytes. - ReadPointerAsBytes, + ReadPartialPointer(Pointer), + /// Encountered a pointer where we needed an integer. + ReadPointerAsInt(Option<(AllocId, BadBytesAccess)>), /// Accessing thread local statics ThreadLocalStatic(DefId), /// Accessing an unsupported extern static. @@ -497,7 +493,7 @@ impl InterpError<'_> { matches!( self, InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) - | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Validation { .. }) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. }) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) ) } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 8b5a8d1730106..9f7b6b811cf43 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -142,11 +142,11 @@ use crate::ty::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, - EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, - InvalidProgramInfo, MachineStopType, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, - ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, - ValidationErrorInfo, ValidationErrorKind, + struct_error, BadBytesAccess, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, + EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, + InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, PointerKind, + ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, + UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 20861d5ffa405..5345a65880328 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -378,15 +378,16 @@ impl<'tcx, Prov: Provenance> Scalar { #[inline] pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); - self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err( - |size| { + self.try_to_int() + .map_err(|_| err_unsup!(ReadPointerAsInt(None)))? + .to_bits(target_size) + .map_err(|size| { err_ub!(ScalarSizeMismatch(ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes(), })) .into() - }, - ) + }) } #[inline(always)] diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 8d9901807eccc..6bd4be91e516b 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -273,6 +273,8 @@ pub fn report_error<'tcx, 'mir>( } else { #[rustfmt::skip] let title = match e.kind() { + UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(e)) if matches!(e.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) => + bug!("This validation error should be impossible in Miri: {:?}", e.kind), UndefinedBehavior(_) => "Undefined Behavior", ResourceExhaustion(_) => @@ -377,7 +379,7 @@ pub fn report_error<'tcx, 'mir>( if let Some((alloc_id, access)) = extra { eprintln!( "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:", - range = access.uninit, + range = access.bad, ); eprintln!("{:?}", ecx.dump_alloc(alloc_id)); } diff --git a/src/tools/miri/tests/fail/validity/uninit_float.stderr b/src/tools/miri/tests/fail/validity/uninit_float.stderr index 677a0fc5570d7..e95e3b18128d2 100644 --- a/src/tools/miri/tests/fail/validity/uninit_float.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number --> $DIR/uninit_float.rs:LL:CC | LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/validity/uninit_integer.stderr b/src/tools/miri/tests/fail/validity/uninit_integer.stderr index a9ac2a6dc67e7..2156886cd71c1 100644 --- a/src/tools/miri/tests/fail/validity/uninit_integer.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_integer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer --> $DIR/uninit_integer.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 22c3dfa64febc..294bc77aa3174 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -41,7 +41,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/forbidden_slices.rs:26:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -52,8 +52,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/forbidden_slices.rs:28:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -75,7 +76,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/forbidden_slices.rs:33:1 | LL | pub static S7: &[u16] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -143,7 +144,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/forbidden_slices.rs:53:1 | LL | pub static R4: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -154,8 +155,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/forbidden_slices.rs:58:1 | LL | pub static R5: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index bf98d03946d81..f099bc7ef7c35 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:26:49 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:29:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:32:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -29,7 +29,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:35:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -38,7 +38,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:38:45 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -53,7 +53,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:45:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -62,7 +62,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:48:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -71,7 +71,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:51:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -80,7 +80,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:54:45 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -95,7 +95,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:61:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -104,7 +104,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:64:45 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -113,7 +113,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:67:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -122,7 +122,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:70:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -131,7 +131,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:73:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -140,7 +140,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:76:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -149,7 +149,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:79:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -158,7 +158,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:82:41 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -167,7 +167,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:85:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -176,7 +176,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:88:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -185,7 +185,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:91:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -194,7 +194,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:94:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -203,7 +203,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:97:41 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -212,7 +212,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:100:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -221,7 +221,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:103:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -230,7 +230,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:106:41 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -239,7 +239,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:109:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -248,7 +248,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-pointer-values-in-various-types.rs:112:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index 8a5424b3a6c67..e087a0ebec7f4 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -266,7 +266,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:144:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -277,7 +277,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:146:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -288,8 +288,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } @@ -516,7 +517,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:215:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -527,8 +528,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:218:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } @@ -550,7 +552,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:225:1 | LL | pub static S7: &[u16] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -561,7 +563,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:232:1 | LL | pub static R4: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -572,8 +574,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:237:1 | LL | pub static R5: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 08b98b37bd819..4c655161f7983 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -266,7 +266,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:144:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -277,7 +277,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:146:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -288,8 +288,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -516,7 +517,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:215:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -527,8 +528,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:218:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -550,7 +552,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:225:1 | LL | pub static S7: &[u16] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -561,7 +563,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:232:1 | LL | pub static R4: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -572,8 +574,9 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:237:1 | LL | pub static R5: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr index eaa2d6b279451..8175fe6016ab8 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr index eaa2d6b279451..8175fe6016ab8 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.32bit.stderr index 5ef0d0146f2f5..c0ad6caecf2ba 100644 --- a/tests/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.32bit.stderr @@ -13,7 +13,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -22,7 +22,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:33:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -42,7 +42,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -51,7 +51,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -66,7 +66,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:64:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr index c28a1b722aef6..6db43d379d153 100644 --- a/tests/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.64bit.stderr @@ -13,7 +13,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -22,7 +22,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:33:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -42,7 +42,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -51,7 +51,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -66,7 +66,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:64:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ub-int-array.32bit.stderr b/tests/ui/consts/const-eval/ub-int-array.32bit.stderr index edcde13b0e037..b3df41304ac33 100644 --- a/tests/ui/consts/const-eval/ub-int-array.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-int-array.32bit.stderr @@ -1,20 +1,35 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/ub-int-array.rs:15:9 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-int-array.rs:19:1 | -LL | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_INT_0: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected an integer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 12, align: 4) { + __ __ __ __ 01 00 00 00 02 00 00 00 │ ░░░░........ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-int-array.rs:30:13 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-int-array.rs:24:1 + | +LL | const UNINIT_INT_1: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer | -LL | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 12, align: 4) { + 00 00 00 00 01 __ 01 01 02 02 __ 02 │ .....░....░. + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-int-array.rs:56:13 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-int-array.rs:42:1 + | +LL | const UNINIT_INT_2: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: encountered uninitialized memory, but expected an integer | -LL | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 12, align: 4) { + 00 00 00 00 01 01 01 01 02 02 02 __ │ ...........░ + } error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/ub-int-array.64bit.stderr b/tests/ui/consts/const-eval/ub-int-array.64bit.stderr index edcde13b0e037..b3df41304ac33 100644 --- a/tests/ui/consts/const-eval/ub-int-array.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-int-array.64bit.stderr @@ -1,20 +1,35 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/ub-int-array.rs:15:9 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-int-array.rs:19:1 | -LL | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_INT_0: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected an integer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 12, align: 4) { + __ __ __ __ 01 00 00 00 02 00 00 00 │ ░░░░........ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-int-array.rs:30:13 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-int-array.rs:24:1 + | +LL | const UNINIT_INT_1: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer | -LL | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 12, align: 4) { + 00 00 00 00 01 __ 01 01 02 02 __ 02 │ .....░....░. + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-int-array.rs:56:13 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-int-array.rs:42:1 + | +LL | const UNINIT_INT_2: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: encountered uninitialized memory, but expected an integer | -LL | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 12, align: 4) { + 00 00 00 00 01 01 01 01 02 02 02 __ │ ...........░ + } error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/ub-int-array.rs b/tests/ui/consts/const-eval/ub-int-array.rs index a68d3fb17bcfc..adcf376b9c765 100644 --- a/tests/ui/consts/const-eval/ub-int-array.rs +++ b/tests/ui/consts/const-eval/ub-int-array.rs @@ -10,54 +10,52 @@ union MaybeUninit { init: T, } +impl MaybeUninit { + const fn new(t: T) -> Self { + MaybeUninit { init: t } + } +} + const UNINIT_INT_0: [u32; 3] = unsafe { - [ - MaybeUninit { uninit: () }.init, - //~^ ERROR evaluation of constant value failed - //~| uninitialized - 1, - 2, - ] + //~^ ERROR it is undefined behavior to use this value + //~| invalid value at [0] + mem::transmute([MaybeUninit { uninit: () }, MaybeUninit::new(1), MaybeUninit::new(2)]) }; const UNINIT_INT_1: [u32; 3] = unsafe { - mem::transmute( - [ - 0u8, - 0u8, - 0u8, - 0u8, - 1u8, - MaybeUninit { uninit: () }.init, - //~^ ERROR evaluation of constant value failed - //~| uninitialized - 1u8, - 1u8, - 2u8, - 2u8, - MaybeUninit { uninit: () }.init, - 2u8, - ] - ) + //~^ ERROR it is undefined behavior to use this value + //~| invalid value at [1] + mem::transmute([ + MaybeUninit::new(0u8), + MaybeUninit::new(0u8), + MaybeUninit::new(0u8), + MaybeUninit::new(0u8), + MaybeUninit::new(1u8), + MaybeUninit { uninit: () }, + MaybeUninit::new(1u8), + MaybeUninit::new(1u8), + MaybeUninit::new(2u8), + MaybeUninit::new(2u8), + MaybeUninit { uninit: () }, + MaybeUninit::new(2u8), + ]) }; const UNINIT_INT_2: [u32; 3] = unsafe { - mem::transmute( - [ - 0u8, - 0u8, - 0u8, - 0u8, - 1u8, - 1u8, - 1u8, - 1u8, - 2u8, - 2u8, - 2u8, - MaybeUninit { uninit: () }.init, - //~^ ERROR evaluation of constant value failed - //~| uninitialized - ] - ) + //~^ ERROR it is undefined behavior to use this value + //~| invalid value at [2] + mem::transmute([ + MaybeUninit::new(0u8), + MaybeUninit::new(0u8), + MaybeUninit::new(0u8), + MaybeUninit::new(0u8), + MaybeUninit::new(1u8), + MaybeUninit::new(1u8), + MaybeUninit::new(1u8), + MaybeUninit::new(1u8), + MaybeUninit::new(2u8), + MaybeUninit::new(2u8), + MaybeUninit::new(2u8), + MaybeUninit { uninit: () }, + ]) }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index d1644f8a4dc1f..0ee1e60877f6f 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -46,7 +46,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-ref-ptr.rs:33:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -55,7 +55,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-ref-ptr.rs:36:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -70,7 +70,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-ref-ptr.rs:39:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index f38e7916b7553..02bbbf5043594 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-wide-ptr.rs:43:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -33,7 +33,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-wide-ptr.rs:46:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -53,7 +53,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:52:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -64,7 +64,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:55:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -103,7 +103,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -123,7 +123,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-wide-ptr.rs:81:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs index 5bff34bbe9338..37b37e9659e5e 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -1,7 +1,7 @@ // revisions: no_flag with_flag // [no_flag] check-pass // [with_flag] compile-flags: -Zextra-const-ub-checks -#![feature(never_type)] +#![feature(never_type, pointer_byte_offsets)] use std::mem::transmute; use std::ptr::addr_of; @@ -12,6 +12,9 @@ enum E { A, B } #[derive(Clone, Copy)] enum Never {} +#[repr(usize)] +enum PtrSizedEnum { V } + // An enum with uninhabited variants but also at least 2 inhabited variants -- so the uninhabited // variants *do* have a discriminant. #[derive(Clone, Copy)] @@ -31,12 +34,20 @@ const INVALID_BOOL: () = unsafe { const INVALID_PTR_IN_INT: () = unsafe { let _x: usize = transmute(&3u8); //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +const INVALID_PTR_IN_ENUM: () = unsafe { + let _x: PtrSizedEnum = transmute(&3u8); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value }; const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe { let x: &[u8] = &[0; 32]; let _x: (usize, usize) = transmute(x); //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value }; const UNALIGNED_PTR: () = unsafe { @@ -50,6 +61,27 @@ const UNINHABITED_VARIANT: () = unsafe { // Not using transmute, we want to hit the ImmTy code path. let v = *addr_of!(data).cast::(); //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +const PARTIAL_POINTER: () = unsafe { + #[repr(C, packed)] + struct Packed { + pad1: u8, + ptr: *const u8, + pad2: [u8; 7], + } + // `Align` ensures that the entire thing has pointer alignment again. + #[repr(C)] + struct Align { + p: Packed, + align: usize, + } + let mem = Packed { pad1: 0, ptr: &0u8 as *const u8, pad2: [0; 7] }; + let mem = Align { p: mem, align: 0 }; + let _val = *(&mem as *const Align as *const [*const u8; 2]); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value }; // Regression tests for an ICE (related to ). diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index 19f1748ff9c96..4ee12d501e880 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -1,39 +1,57 @@ error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:26:20 + --> $DIR/detect-extra-ub.rs:29:20 | LL | let _x: bool = transmute(3u8); | ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:32:21 + --> $DIR/detect-extra-ub.rs:35:21 | LL | let _x: usize = transmute(&3u8); - | ^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected an integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:38:30 + --> $DIR/detect-extra-ub.rs:41:28 + | +LL | let _x: PtrSizedEnum = transmute(&3u8); + | ^^^^^^^^^^^^^^^ constructing invalid value at .: encountered a pointer, but expected an integer + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:48:30 | LL | let _x: (usize, usize) = transmute(x); - | ^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^ constructing invalid value at .0: encountered a pointer, but expected an integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:43:20 + --> $DIR/detect-extra-ub.rs:54:20 | LL | let _x: &u32 = transmute(&[0u8; 4]); | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:51:13 + --> $DIR/detect-extra-ub.rs:62:13 | LL | let v = *addr_of!(data).cast::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant -error: aborting due to 5 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:82:16 + | +LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a partial pointer or a mix of pointers + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-83182.rs b/tests/ui/consts/issue-83182.rs deleted file mode 100644 index b62f903bdc270..0000000000000 --- a/tests/ui/consts/issue-83182.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Strip out raw byte dumps to make comparison platform-independent: -// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" - -use std::mem; -struct MyStr(str); -const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; -//~^ ERROR: it is undefined behavior to use this value -fn main() {} diff --git a/tests/ui/consts/issue-83182.stderr b/tests/ui/consts/issue-83182.stderr deleted file mode 100644 index ca4e0f7aa0239..0000000000000 --- a/tests/ui/consts/issue-83182.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/issue-83182.rs:7:1 - | -LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes - | - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr index 67797e6fb5a85..af0f77c6767b4 100644 --- a/tests/ui/consts/issue-miri-1910.stderr +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -1,7 +1,7 @@ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: unable to turn pointer into raw bytes + = note: unable to turn pointer into integer | note: inside `std::ptr::read::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.rs b/tests/ui/consts/miri_unleashed/ptr_arith.rs index 4d12960b86ba3..5cda3c41152cd 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.rs +++ b/tests/ui/consts/miri_unleashed/ptr_arith.rs @@ -1,5 +1,5 @@ // compile-flags: -Zunleash-the-miri-inside-of-you -#![feature(core_intrinsics)] +#![feature(core_intrinsics, pointer_byte_offsets)] // During CTFE, we prevent pointer-to-int casts. // Pointer comparisons are prevented in the trait system. @@ -15,7 +15,7 @@ static PTR_INT_TRANSMUTE: () = unsafe { let x: usize = std::mem::transmute(&0); let _v = x + 0; //~^ ERROR could not evaluate static initializer - //~| unable to turn pointer into raw bytes + //~| unable to turn pointer into integer }; // I'd love to test pointer comparison, but that is not possible since diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.stderr b/tests/ui/consts/miri_unleashed/ptr_arith.stderr index 30fd3a55e85be..25ca6bc4eaadb 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/tests/ui/consts/miri_unleashed/ptr_arith.stderr @@ -8,7 +8,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ptr_arith.rs:16:14 | LL | let _v = x + 0; - | ^ unable to turn pointer into raw bytes + | ^ unable to turn pointer into integer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs new file mode 100644 index 0000000000000..0e894ef581c38 --- /dev/null +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs @@ -0,0 +1,17 @@ +#![feature(core_intrinsics)] +#![feature(const_intrinsic_raw_eq)] + +const RAW_EQ_PADDING: bool = unsafe { + std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) +//~^ ERROR evaluation of constant value failed +//~| requires initialized memory +}; + +const RAW_EQ_PTR: bool = unsafe { + std::intrinsics::raw_eq(&(&0), &(&1)) +//~^ ERROR evaluation of constant value failed +//~| `raw_eq` on bytes with provenance +}; + +pub fn main() { +} diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr similarity index 54% rename from tests/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr rename to tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index 56d5a48573e26..4fc304cda604e 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -1,9 +1,15 @@ error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-padding.rs:5:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:5:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory -error: aborting due to previous error +error[E0080]: evaluation of constant value failed + --> $DIR/intrinsic-raw_eq-const-bad.rs:11:5 + | +LL | std::intrinsics::raw_eq(&(&0), &(&1)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `raw_eq` on bytes with provenance + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs deleted file mode 100644 index a93d777d28656..0000000000000 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(core_intrinsics)] -#![feature(const_intrinsic_raw_eq)] - -const BAD_RAW_EQ_CALL: bool = unsafe { - std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) -//~^ ERROR evaluation of constant value failed -}; - -pub fn main() { -} From 6ae2677d72f1bc2b239ecfbfa1bb8d672fbfd211 Mon Sep 17 00:00:00 2001 From: Taras Tsugrii Date: Wed, 2 Aug 2023 20:51:16 -0700 Subject: [PATCH 12/19] [rustc_span][perf] Hoist lookup sorted by words out of the loop. @lqd commented on https://github.com/rust-lang/rust/pull/114351 asking if `sort_by_words(lookup)` is computed repeatedly. I was assuming that rustc should have no difficulties to hoist it automatically outside of the loop to avoid repeated pure computation, but according to https://godbolt.org/z/frs8Kj1rq it seems like I was wrong: original version seems to have 2 calls per loop iteration ``` .LBB16_3: mov rbx, qword ptr [r13] mov r14, qword ptr [r13 + 8] lea rdi, [rsp + 40] mov rsi, rbx mov rdx, r14 call example::sort_by_words lea rdi, [rsp + 64] mov rsi, qword ptr [rsp + 8] mov rdx, qword ptr [rsp + 16] call example::sort_by_words mov rdi, qword ptr [rsp + 40] mov rdx, qword ptr [rsp + 56] mov rsi, qword ptr [rsp + 64] cmp rdx, qword ptr [rsp + 80] mov qword ptr [rsp + 32], rdi mov qword ptr [rsp + 24], rsi jne .LBB16_5 call qword ptr [rip + bcmp@GOTPCREL] test eax, eax sete al mov dword ptr [rsp + 4], eax mov rsi, qword ptr [rsp + 72] test rsi, rsi jne .LBB16_8 jmp .LBB16_9 ``` but the manually hoisted version just 1: ``` .LBB16_3: mov r13, qword ptr [r15] mov r14, qword ptr [r15 + 8] lea rdi, [rsp + 64] mov rsi, r13 mov rdx, r14 call example::sort_by_words mov rdi, qword ptr [rsp + 64] mov rdx, qword ptr [rsp + 16] cmp qword ptr [rsp + 80], rdx mov qword ptr [rsp + 32], rdi jne .LBB16_5 mov rsi, qword ptr [rsp + 8] call qword ptr [rip + bcmp@GOTPCREL] test eax, eax sete bpl mov rsi, qword ptr [rsp + 72] test rsi, rsi jne .LBB16_8 jmp .LBB16_9 ``` This code is probably not very hot, but there is no reason to leave such a low hanging fruit. --- compiler/rustc_span/src/edit_distance.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 259f423865480..4811bb2c35489 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -238,8 +238,9 @@ fn find_best_match_for_name_impl( } fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option { + let lookup_sorted_by_words = sort_by_words(lookup); iter_names.iter().fold(None, |result, candidate| { - if sort_by_words(candidate.as_str()) == sort_by_words(lookup) { + if sort_by_words(candidate.as_str()) == lookup_sorted_by_words { Some(*candidate) } else { result From 41e85c3d2369ebc44c19c6009a061b64d43672ee Mon Sep 17 00:00:00 2001 From: r0cky Date: Thu, 3 Aug 2023 05:18:19 +0000 Subject: [PATCH 13/19] Apply suggestions --- compiler/rustc_parse/src/parser/pat.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 615ef28db085d..5803d0c1c0524 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -139,7 +139,7 @@ impl<'a> Parser<'a> { }; // Parse the first pattern (`p_0`). - let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc.clone())?; + let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?; if rc == RecoverComma::Yes { self.maybe_recover_unexpected_comma(first_pat.span, rt)?; } @@ -813,7 +813,9 @@ impl<'a> Parser<'a> { | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. | token::ModSep // A tuple / struct variant pattern. | token::Not)) // A macro expanding to a pattern. - && !(self.look_ahead(1, |t| t.kind == token::Lt) && self.look_ahead(2, |t| t.can_begin_type())) // May suggest the turbofish syntax for generics, only valid for recoveries. + // May suggest the turbofish syntax for generics, only valid for recoveries. + && !(self.look_ahead(1, |t| t.kind == token::Lt) + && self.look_ahead(2, |t| t.can_begin_type())) } /// Parses `ident` or `ident @ pat`. From 2195fa6a9bad1e95511875c93c34b55fe7ae55fa Mon Sep 17 00:00:00 2001 From: bohan Date: Thu, 3 Aug 2023 16:44:02 +0800 Subject: [PATCH 14/19] fix the span in the suggestion of remove question mark --- .../src/infer/error_reporting/mod.rs | 2 +- .../remove-question-symbol-with-paren.rs | 9 ++++++++ .../remove-question-symbol-with-paren.stderr | 22 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/ui/suggestions/remove-question-symbol-with-paren.rs create mode 100644 tests/ui/suggestions/remove-question-symbol-with-paren.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 25077f9bb97ee..7739cf1ee05b0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -764,7 +764,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( - source_map.end_point(cause.span), + source_map.end_point(cause.span()), "try removing this `?`", "", Applicability::MachineApplicable, diff --git a/tests/ui/suggestions/remove-question-symbol-with-paren.rs b/tests/ui/suggestions/remove-question-symbol-with-paren.rs new file mode 100644 index 0000000000000..c522793dbcb7e --- /dev/null +++ b/tests/ui/suggestions/remove-question-symbol-with-paren.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/114392 + +fn foo() -> Option<()> { + let x = Some(()); + (x?) + //~^ ERROR `?` operator has incompatible types +} + +fn main() {} diff --git a/tests/ui/suggestions/remove-question-symbol-with-paren.stderr b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr new file mode 100644 index 0000000000000..39e35f733a1d2 --- /dev/null +++ b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr @@ -0,0 +1,22 @@ +error[E0308]: `?` operator has incompatible types + --> $DIR/remove-question-symbol-with-paren.rs:5:6 + | +LL | (x?) + | ^^ expected `Option<()>`, found `()` + | + = note: `?` operator cannot convert from `()` to `Option<()>` + = note: expected enum `Option<()>` + found unit type `()` +help: try removing this `?` + | +LL - (x?) +LL + (x) + | +help: try wrapping the expression in `Some` + | +LL | (Some(x?)) + | +++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 4b3dadbe5a9f3dd06932a9099abd37bae751cdd3 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 13 Jul 2023 14:13:08 +0200 Subject: [PATCH 15/19] Also lint on cast/cast_mut and ptr::from_mut/ptr::from_ref --- compiler/rustc_lint/src/ptr_nulls.rs | 52 +++++++++++----- tests/ui/consts/ptr_is_null.rs | 1 + tests/ui/lint/ptr_null_checks.rs | 16 +++++ tests/ui/lint/ptr_null_checks.stderr | 88 +++++++++++++++++++++------- 4 files changed, 121 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index b2138c42224b4..64b86fec46b42 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -31,25 +31,45 @@ declare_lint! { declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]); -fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option> { - let mut expr = expr.peel_blocks(); +/// This function detects and returns the original expression from a series of consecutive casts, +/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`. +fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> { let mut had_at_least_one_cast = false; - while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind - && let TyKind::Ptr(_) = cast_ty.kind { - expr = cast_expr.peel_blocks(); - had_at_least_one_cast = true; + loop { + e = e.peel_blocks(); + e = if let ExprKind::Cast(expr, t) = e.kind + && let TyKind::Ptr(_) = t.kind { + had_at_least_one_cast = true; + expr + } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) { + had_at_least_one_cast = true; + expr + } else if let ExprKind::Call(path, [arg]) = e.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::ptr_from_mut)) { + had_at_least_one_cast = true; + arg + } else if had_at_least_one_cast { + return Some(e); + } else { + return None; + }; } - if !had_at_least_one_cast { - None +} + +fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option> { + let expr = ptr_cast_chain(cx, expr)?; + + let orig_ty = cx.typeck_results().expr_ty(expr); + if orig_ty.is_fn() { + Some(PtrNullChecksDiag::FnPtr) + } else if orig_ty.is_ref() { + Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span }) } else { - let orig_ty = cx.typeck_results().expr_ty(expr); - if orig_ty.is_fn() { - Some(PtrNullChecksDiag::FnPtr) - } else if orig_ty.is_ref() { - Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span }) - } else { - None - } + None } } diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs index 8babb68585dea..43b9767db1645 100644 --- a/tests/ui/consts/ptr_is_null.rs +++ b/tests/ui/consts/ptr_is_null.rs @@ -2,6 +2,7 @@ // check-pass #![feature(const_ptr_is_null)] +#![allow(useless_ptr_null_checks)] const FOO: &usize = &42; diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs index 600ca32ca8937..e677ea3094d5e 100644 --- a/tests/ui/lint/ptr_null_checks.rs +++ b/tests/ui/lint/ptr_null_checks.rs @@ -1,5 +1,9 @@ // check-pass +#![feature(ptr_from_ref)] + +use std::ptr; + extern "C" fn c_fn() {} fn static_i32() -> &'static i32 { &1 } @@ -21,6 +25,10 @@ fn main() { //~^ WARN function pointers are not nullable if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} //~^ WARN function pointers are not nullable + if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {} + //~^ WARN function pointers are not nullable + if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {} + //~^ WARN function pointers are not nullable if (fn_ptr as fn() as *const ()).is_null() {} //~^ WARN function pointers are not nullable if (c_fn as *const fn()).is_null() {} @@ -29,8 +37,16 @@ fn main() { // ---------------- References ------------------ if (&mut 8 as *mut i32).is_null() {} //~^ WARN references are not nullable + if ptr::from_mut(&mut 8).is_null() {} + //~^ WARN references are not nullable if (&8 as *const i32).is_null() {} //~^ WARN references are not nullable + if ptr::from_ref(&8).is_null() {} + //~^ WARN references are not nullable + if ptr::from_ref(&8).cast_mut().is_null() {} + //~^ WARN references are not nullable + if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {} + //~^ WARN references are not nullable if (&8 as *const i32) == std::ptr::null() {} //~^ WARN references are not nullable let ref_num = &8; diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr index 10efa8685befd..525d96c491972 100644 --- a/tests/ui/lint/ptr_null_checks.stderr +++ b/tests/ui/lint/ptr_null_checks.stderr @@ -1,5 +1,5 @@ warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:10:8 + --> $DIR/ptr_null_checks.rs:14:8 | LL | if (fn_ptr as *mut ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | if (fn_ptr as *mut ()).is_null() {} = note: `#[warn(useless_ptr_null_checks)]` on by default warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:12:8 + --> $DIR/ptr_null_checks.rs:16:8 | LL | if (fn_ptr as *const u8).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | if (fn_ptr as *const u8).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:14:8 + --> $DIR/ptr_null_checks.rs:18:8 | LL | if (fn_ptr as *const ()) == std::ptr::null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | if (fn_ptr as *const ()) == std::ptr::null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:16:8 + --> $DIR/ptr_null_checks.rs:20:8 | LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:18:8 + --> $DIR/ptr_null_checks.rs:22:8 | LL | if (fn_ptr as *const ()) == (0 as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | if (fn_ptr as *const ()) == (0 as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:20:8 + --> $DIR/ptr_null_checks.rs:24:8 | LL | if <*const _>::is_null(fn_ptr as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | if <*const _>::is_null(fn_ptr as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:22:8 + --> $DIR/ptr_null_checks.rs:26:8 | LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,23 @@ LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:24:8 + --> $DIR/ptr_null_checks.rs:28:8 + | +LL | if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value + +warning: function pointers are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:30:8 + | +LL | if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value + +warning: function pointers are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:32:8 | LL | if (fn_ptr as fn() as *const ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +80,7 @@ LL | if (fn_ptr as fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:26:8 + --> $DIR/ptr_null_checks.rs:34:8 | LL | if (c_fn as *const fn()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +88,7 @@ LL | if (c_fn as *const fn()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:30:8 + --> $DIR/ptr_null_checks.rs:38:8 | LL | if (&mut 8 as *mut i32).is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +96,15 @@ LL | if (&mut 8 as *mut i32).is_null() {} | expression has type `&mut i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:32:8 + --> $DIR/ptr_null_checks.rs:40:8 + | +LL | if ptr::from_mut(&mut 8).is_null() {} + | ^^^^^^^^^^^^^^------^^^^^^^^^^^ + | | + | expression has type `&mut i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:42:8 | LL | if (&8 as *const i32).is_null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +112,31 @@ LL | if (&8 as *const i32).is_null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:34:8 + --> $DIR/ptr_null_checks.rs:44:8 + | +LL | if ptr::from_ref(&8).is_null() {} + | ^^^^^^^^^^^^^^--^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:46:8 + | +LL | if ptr::from_ref(&8).cast_mut().is_null() {} + | ^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:48:8 + | +LL | if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {} + | ^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `&i32` + +warning: references are not nullable, so checking them for null will always return false + --> $DIR/ptr_null_checks.rs:50:8 | LL | if (&8 as *const i32) == std::ptr::null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +144,7 @@ LL | if (&8 as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:37:8 + --> $DIR/ptr_null_checks.rs:53:8 | LL | if (ref_num as *const i32) == std::ptr::null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +152,7 @@ LL | if (ref_num as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:39:8 + --> $DIR/ptr_null_checks.rs:55:8 | LL | if (b"\0" as *const u8).is_null() {} | ^-----^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +160,7 @@ LL | if (b"\0" as *const u8).is_null() {} | expression has type `&[u8; 1]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:41:8 + --> $DIR/ptr_null_checks.rs:57:8 | LL | if ("aa" as *const str).is_null() {} | ^----^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +168,7 @@ LL | if ("aa" as *const str).is_null() {} | expression has type `&str` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:43:8 + --> $DIR/ptr_null_checks.rs:59:8 | LL | if (&[1, 2] as *const i32).is_null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,7 +176,7 @@ LL | if (&[1, 2] as *const i32).is_null() {} | expression has type `&[i32; 2]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:45:8 + --> $DIR/ptr_null_checks.rs:61:8 | LL | if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} | ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +184,7 @@ LL | if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} | expression has type `&mut [i32; 2]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:47:8 + --> $DIR/ptr_null_checks.rs:63:8 | LL | if (static_i32() as *const i32).is_null() {} | ^------------^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,12 +192,12 @@ LL | if (static_i32() as *const i32).is_null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:49:8 + --> $DIR/ptr_null_checks.rs:65:8 | LL | if (&*{ static_i32() } as *const i32).is_null() {} | ^------------------^^^^^^^^^^^^^^^^^^^^^^^^^ | | | expression has type `&i32` -warning: 19 warnings emitted +warning: 25 warnings emitted From 8c8af6cf99d6a54ece11d21c15e909aef2b60552 Mon Sep 17 00:00:00 2001 From: r0cky Date: Thu, 3 Aug 2023 08:56:31 +0000 Subject: [PATCH 16/19] Avoid too many expected symbols and reduce `None`s --- compiler/rustc_parse/src/parser/attr.rs | 4 +- .../rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 6 +-- compiler/rustc_parse/src/parser/item.rs | 6 +-- compiler/rustc_parse/src/parser/mod.rs | 6 +-- .../rustc_parse/src/parser/nonterminal.rs | 2 +- compiler/rustc_parse/src/parser/pat.rs | 43 ++++++++++++------- compiler/rustc_parse/src/parser/path.rs | 33 +++----------- compiler/rustc_parse/src/parser/stmt.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 6 +-- tests/ui/span/issue-34264.stderr | 4 +- .../suggestions/issue-64252-self-type.stderr | 8 ++-- 12 files changed, 58 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 1271bce799d5c..ee0abba1c1753 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -260,7 +260,7 @@ impl<'a> Parser<'a> { item } else { let do_parse = |this: &mut Self| { - let path = this.parse_path(PathStyle::Mod, None)?; + let path = this.parse_path(PathStyle::Mod)?; let args = this.parse_attr_args()?; Ok(ast::AttrItem { path, args, tokens: None }) }; @@ -387,7 +387,7 @@ impl<'a> Parser<'a> { } let lo = self.token.span; - let path = self.parse_path(PathStyle::Mod, None)?; + let path = self.parse_path(PathStyle::Mod)?; let kind = self.parse_meta_item_kind()?; let span = lo.to(self.prev_token.span); Ok(ast::MetaItem { path, kind, span }) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 8bc4433a9653a..5fa4f7902d624 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1579,7 +1579,7 @@ impl<'a> Parser<'a> { self.expect(&token::ModSep)?; let mut path = ast::Path { segments: ThinVec::new(), span: DUMMY_SP, tokens: None }; - self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None, None)?; + self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?; path.span = ty_span.to(self.prev_token.span); let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty)); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 6dafb8b999b2f..0e19a67a8413a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -775,7 +775,7 @@ impl<'a> Parser<'a> { _ => {} } - match self.parse_path(PathStyle::Expr, None) { + match self.parse_path(PathStyle::Expr) { Ok(path) => { let span_after_type = parser_snapshot_after_type.token.span; let expr = mk_expr( @@ -1314,7 +1314,7 @@ impl<'a> Parser<'a> { } let fn_span_lo = self.token.span; - let mut seg = self.parse_path_segment(PathStyle::Expr, None, None)?; + let mut seg = self.parse_path_segment(PathStyle::Expr, None)?; self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]); self.check_turbofish_missing_angle_brackets(&mut seg); @@ -1544,7 +1544,7 @@ impl<'a> Parser<'a> { })?; (Some(qself), path) } else { - (None, self.parse_path(PathStyle::Expr, None)?) + (None, self.parse_path(PathStyle::Expr)?) }; // `!`, as an operator, is prefix, so we know this isn't that. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d3f756139def3..1301ed3e3882e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -452,7 +452,7 @@ impl<'a> Parser<'a> { /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { - let path = self.parse_path(PathStyle::Mod, None)?; // `foo::bar` + let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` self.expect(&token::Not)?; // `!` match self.parse_delim_args() { // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`. @@ -976,7 +976,7 @@ impl<'a> Parser<'a> { self.parse_use_tree_glob_or_nested()? } else { // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` - prefix = self.parse_path(PathStyle::Mod, None)?; + prefix = self.parse_path(PathStyle::Mod)?; if self.eat(&token::ModSep) { self.parse_use_tree_glob_or_nested()? @@ -987,7 +987,7 @@ impl<'a> Parser<'a> { .emit_err(errors::SingleColonImportPath { span: self.prev_token.span }); // We parse the rest of the path and append it to the original prefix. - self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None, None)?; + self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?; prefix.span = lo.to(self.prev_token.span); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2af0caa1bdaf7..37b4c371c94b4 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1413,7 +1413,7 @@ impl<'a> Parser<'a> { // Parse `pub(in path)`. self.bump(); // `(` self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod, None)?; // `path` + let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), @@ -1430,7 +1430,7 @@ impl<'a> Parser<'a> { { // Parse `pub(crate)`, `pub(self)`, or `pub(super)`. self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod, None)?; // `crate`/`super`/`self` + let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), @@ -1456,7 +1456,7 @@ impl<'a> Parser<'a> { /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod, None)?; + let path = self.parse_path(PathStyle::Mod)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` let path_str = pprust::path_to_string(&path); diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index a09c1e4d7fde2..f5681532b3af7 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -168,7 +168,7 @@ impl<'a> Parser<'a> { }.into_diagnostic(&self.sess.span_diagnostic)); } NonterminalKind::Path => token::NtPath( - P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type, None))?), + P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?), ), NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item(true)?)), NonterminalKind::Vis => token::NtVis( diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 5803d0c1c0524..8d68a3a50acae 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -2,10 +2,11 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; use crate::errors::{ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, - ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, - InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, - RemoveLet, RepeatedMutInPattern, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, + ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, + InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, + PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, + TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, + UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -366,11 +367,11 @@ impl<'a> Parser<'a> { // Parse _ PatKind::Wild } else if self.eat_keyword(kw::Mut) { - self.parse_pat_ident_mut()? + self.parse_pat_ident_mut(syntax_loc)? } else if self.eat_keyword(kw::Ref) { // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); - self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))? + self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)? } else if self.eat_keyword(kw::Box) { self.parse_pat_box()? } else if self.check_inline_const(0) { @@ -392,7 +393,7 @@ impl<'a> Parser<'a> { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. - self.parse_pat_ident(BindingAnnotation::NONE)? + self.parse_pat_ident(BindingAnnotation::NONE, syntax_loc)? } else if self.is_start_of_pat_with_path() { // Parse pattern starting with a path let (qself, path) = if self.eat_lt() { @@ -401,7 +402,7 @@ impl<'a> Parser<'a> { (Some(qself), path) } else { // Parse an unqualified path - (None, self.parse_path(PathStyle::Pat, syntax_loc)?) + (None, self.parse_path(PathStyle::Pat)?) }; let span = lo.to(self.prev_token.span); @@ -574,12 +575,12 @@ impl<'a> Parser<'a> { } /// Parse a mutable binding with the `mut` token already eaten. - fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> { + fn parse_pat_ident_mut(&mut self, syntax_loc: Option) -> PResult<'a, PatKind> { let mut_span = self.prev_token.span; if self.eat_keyword(kw::Ref) { self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) }); - return self.parse_pat_ident(BindingAnnotation::REF_MUT); + return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc); } self.recover_additional_muts(); @@ -784,7 +785,7 @@ impl<'a> Parser<'a> { (Some(qself), path) } else { // Parse an unqualified path - (None, self.parse_path(PathStyle::Pat, None)?) + (None, self.parse_path(PathStyle::Pat)?) }; let hi = self.prev_token.span; Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path))) @@ -813,16 +814,28 @@ impl<'a> Parser<'a> { | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. | token::ModSep // A tuple / struct variant pattern. | token::Not)) // A macro expanding to a pattern. - // May suggest the turbofish syntax for generics, only valid for recoveries. - && !(self.look_ahead(1, |t| t.kind == token::Lt) - && self.look_ahead(2, |t| t.can_begin_type())) } /// Parses `ident` or `ident @ pat`. /// Used by the copy foo and ref foo patterns to give a good /// error message when parsing mistakes like `ref foo(a, b)`. - fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> { + fn parse_pat_ident( + &mut self, + binding_annotation: BindingAnnotation, + syntax_loc: Option, + ) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; + + if !matches!(syntax_loc, Some(PatternLocation::FunctionParameter)) + && self.check_noexpect(&token::Lt) + && self.look_ahead(1, |t| t.can_begin_type()) + { + return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax { + span: self.token.span, + suggest_turbofish: self.token.span.shrink_to_lo(), + })); + } + let sub = if self.eat(&token::At) { Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?) } else { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 0d5f48e424e2c..feb7e829caf68 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,7 +1,6 @@ -use super::pat::PatternLocation; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::errors::{GenericArgsInPatRequireTurbofishSyntax, PathSingleColon}; +use crate::errors::PathSingleColon; use crate::{errors, maybe_whole}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -80,7 +79,7 @@ impl<'a> Parser<'a> { let (mut path, path_span); if self.eat_keyword(kw::As) { let path_lo = self.token.span; - path = self.parse_path(PathStyle::Type, None)?; + path = self.parse_path(PathStyle::Type)?; path_span = path_lo.to(self.prev_token.span); } else { path_span = self.token.span.to(self.token.span); @@ -99,7 +98,7 @@ impl<'a> Parser<'a> { } let qself = P(QSelf { ty, path_span, position: path.segments.len() }); - self.parse_path_segments(&mut path.segments, style, None, None)?; + self.parse_path_segments(&mut path.segments, style, None)?; Ok(( qself, @@ -140,12 +139,8 @@ impl<'a> Parser<'a> { true } - pub(super) fn parse_path( - &mut self, - style: PathStyle, - syntax_loc: Option, - ) -> PResult<'a, Path> { - self.parse_path_inner(style, None, syntax_loc) + pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { + self.parse_path_inner(style, None) } /// Parses simple paths. @@ -162,7 +157,6 @@ impl<'a> Parser<'a> { &mut self, style: PathStyle, ty_generics: Option<&Generics>, - syntax_loc: Option, ) -> PResult<'a, Path> { let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| { // Ensure generic arguments don't end up in attribute paths, such as: @@ -207,7 +201,7 @@ impl<'a> Parser<'a> { if self.eat(&token::ModSep) { segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); } - self.parse_path_segments(&mut segments, style, ty_generics, syntax_loc)?; + self.parse_path_segments(&mut segments, style, ty_generics)?; Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None }) } @@ -216,10 +210,9 @@ impl<'a> Parser<'a> { segments: &mut ThinVec, style: PathStyle, ty_generics: Option<&Generics>, - syntax_loc: Option, ) -> PResult<'a, ()> { loop { - let segment = self.parse_path_segment(style, ty_generics, syntax_loc)?; + let segment = self.parse_path_segment(style, ty_generics)?; if style.has_generic_ambiguity() { // In order to check for trailing angle brackets, we must have finished // recursing (`parse_path_segment` can indirectly call this function), @@ -274,7 +267,6 @@ impl<'a> Parser<'a> { &mut self, style: PathStyle, ty_generics: Option<&Generics>, - syntax_loc: Option, ) -> PResult<'a, PathSegment> { let ident = self.parse_path_segment_ident()?; let is_args_start = |token: &Token| { @@ -294,17 +286,6 @@ impl<'a> Parser<'a> { is_args_start(&this.token) }; - if let Some(PatternLocation::FunctionParameter) = syntax_loc { - } else if style == PathStyle::Pat - && self.check_noexpect(&token::Lt) - && self.look_ahead(1, |t| t.can_begin_type()) - { - return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax { - span: self.token.span, - suggest_turbofish: self.token.span.shrink_to_lo(), - })); - } - Ok( if style == PathStyle::Type && check_args_start(self) || style != PathStyle::Mod diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 2c08e984be578..9fcf51a04ec05 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> { let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let path = this.parse_path(PathStyle::Expr, None)?; + let path = this.parse_path(PathStyle::Expr)?; if this.eat(&token::Not) { let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8be84c7d46224..3bb50b05aa346 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -289,7 +289,7 @@ impl<'a> Parser<'a> { recover_return_sign, )? } else { - let path = self.parse_path(PathStyle::Type, None)?; + let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)? } @@ -649,7 +649,7 @@ impl<'a> Parser<'a> { ty_generics: Option<&Generics>, ) -> PResult<'a, TyKind> { // Simple path - let path = self.parse_path_inner(PathStyle::Type, ty_generics, None)?; + let path = self.parse_path_inner(PathStyle::Type, ty_generics)?; if self.eat(&token::Not) { // Macro invocation in type position Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? }))) @@ -865,7 +865,7 @@ impl<'a> Parser<'a> { path } else { - self.parse_path(PathStyle::Type, None)? + self.parse_path(PathStyle::Type)? }; if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) { diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index 8c639d5513b53..f0dea66f6128d 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-34264.rs:1:14 | LL | fn foo(Option, String) {} - | ^ expected one of 9 possible tokens + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name diff --git a/tests/ui/suggestions/issue-64252-self-type.stderr b/tests/ui/suggestions/issue-64252-self-type.stderr index dd83d6a1cb291..dbef39faeadf6 100644 --- a/tests/ui/suggestions/issue-64252-self-type.stderr +++ b/tests/ui/suggestions/issue-64252-self-type.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-64252-self-type.rs:4:15 | LL | pub fn foo(Box) { } - | ^ expected one of 9 possible tokens + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name @@ -14,11 +14,11 @@ help: if this is a type, explicitly ignore the parameter name LL | pub fn foo(_: Box) { } | ++ -error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-64252-self-type.rs:8:15 | LL | fn bar(Box) { } - | ^ expected one of 9 possible tokens + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name From ee519532f69610e208fc61a68537aa662c3e8d16 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 3 Aug 2023 10:57:11 +0200 Subject: [PATCH 17/19] Also add label with original type for function pointers --- compiler/rustc_lint/messages.ftl | 1 + compiler/rustc_lint/src/lints.rs | 6 +++- compiler/rustc_lint/src/ptr_nulls.rs | 2 +- tests/ui/lint/ptr_null_checks.stderr | 44 +++++++++++++++++++++------- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 4897ffd0cece5..027a10de9bb9e 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -449,6 +449,7 @@ lint_path_statement_no_effect = path statement with no effect lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value + .label = expression has type `{$orig_ty}` lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false .label = expression has type `{$orig_ty}` diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 9e1d5605260c3..c0a8d078dc4a6 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -618,7 +618,11 @@ pub struct ExpectationNote { pub enum PtrNullChecksDiag<'a> { #[diag(lint_ptr_null_checks_fn_ptr)] #[help(lint_help)] - FnPtr, + FnPtr { + orig_ty: Ty<'a>, + #[label] + label: Span, + }, #[diag(lint_ptr_null_checks_ref)] Ref { orig_ty: Ty<'a>, diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 64b86fec46b42..02aff91032fd9 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -65,7 +65,7 @@ fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option $DIR/ptr_null_checks.rs:14:8 | LL | if (fn_ptr as *mut ()).is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^------^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value = note: `#[warn(useless_ptr_null_checks)]` on by default @@ -11,7 +13,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:16:8 | LL | if (fn_ptr as *const u8).is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^------^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -19,7 +23,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:18:8 | LL | if (fn_ptr as *const ()) == std::ptr::null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -27,7 +33,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:20:8 | LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -35,7 +43,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:22:8 | LL | if (fn_ptr as *const ()) == (0 as *const ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -43,7 +53,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:24:8 | LL | if <*const _>::is_null(fn_ptr as *const ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -51,7 +63,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:26:8 | LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -59,7 +73,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:28:8 | LL | if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -67,7 +83,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:30:8 | LL | if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn() {main}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -75,7 +93,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:32:8 | LL | if (fn_ptr as fn() as *const ()).is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^--------------^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `fn()` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value @@ -83,7 +103,9 @@ warning: function pointers are not nullable, so checking them for null will alwa --> $DIR/ptr_null_checks.rs:34:8 | LL | if (c_fn as *const fn()).is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^----^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expression has type `extern "C" fn() {c_fn}` | = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value From dce7e87b1646fd5f4f7908fcd0aa1060c5189d44 Mon Sep 17 00:00:00 2001 From: r0cky Date: Thu, 3 Aug 2023 10:34:57 +0000 Subject: [PATCH 18/19] Reduce arbitrary self type suggestions --- .../rustc_parse/src/parser/diagnostics.rs | 18 +++-------------- .../anon-params-denied-2018.stderr | 20 ++++++------------- tests/ui/suggestions/issue-64252-self-type.rs | 7 +++++-- .../suggestions/issue-64252-self-type.stderr | 2 +- 4 files changed, 15 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5fa4f7902d624..00ffa7de2ff62 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2019,7 +2019,7 @@ impl<'a> Parser<'a> { { let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)"; - let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span, maybe_name) = + let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) = match pat.kind { PatKind::Ident(_, ident, _) => ( ident, @@ -2029,7 +2029,6 @@ impl<'a> Parser<'a> { pat.span.shrink_to_lo(), pat.span.shrink_to_hi(), pat.span.shrink_to_lo(), - true, ), // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) @@ -2046,22 +2045,11 @@ impl<'a> Parser<'a> { pat.span.shrink_to_lo(), pat.span, pat.span.shrink_to_lo(), - true, ) } _ => unreachable!(), } - }, - PatKind::Path(_, ref path) if let Some(segment) = path.segments.last() => ( - segment.ident, - "self: ", - ": TypeName".to_string(), - "_: ", - pat.span.shrink_to_lo(), - pat.span.shrink_to_hi(), - pat.span.shrink_to_lo(), - path.segments.len() == 1, // Avoid suggesting that `fn foo(a::b)` is fixed with a change to `fn foo(a::b: TypeName)`. - ), + } _ => { // Otherwise, try to get a type and emit a suggestion. if let Some(ty) = pat.to_ty() { @@ -2089,7 +2077,7 @@ impl<'a> Parser<'a> { } // Avoid suggesting that `fn foo(HashMap)` is fixed with a change to // `fn foo(HashMap: TypeName)`. - if self.token != token::Lt && maybe_name { + if self.token != token::Lt { err.span_suggestion( param_span, "if this is a parameter name, give it a type", diff --git a/tests/ui/anon-params/anon-params-denied-2018.stderr b/tests/ui/anon-params/anon-params-denied-2018.stderr index ede0e70cd7100..bb60c898e8122 100644 --- a/tests/ui/anon-params/anon-params-denied-2018.stderr +++ b/tests/ui/anon-params/anon-params-denied-2018.stderr @@ -45,14 +45,10 @@ LL | fn foo_with_qualified_path(::Baz); | ^ expected one of 8 possible tokens | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn foo_with_qualified_path(self: ::Baz); - | +++++ -help: if this is a type, explicitly ignore the parameter name +help: explicitly ignore the parameter name | LL | fn foo_with_qualified_path(_: ::Baz); - | ++ + | ~~~~~~~~~~~~~~~~~~ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:15:56 @@ -73,14 +69,10 @@ LL | fn foo_with_multiple_qualified_paths(::Baz, ::Baz); | ^ expected one of 8 possible tokens | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn foo_with_multiple_qualified_paths(self: ::Baz, ::Baz); - | +++++ -help: if this is a type, explicitly ignore the parameter name +help: explicitly ignore the parameter name | LL | fn foo_with_multiple_qualified_paths(_: ::Baz, ::Baz); - | ++ + | ~~~~~~~~~~~~~~~~~~ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:18:74 @@ -89,10 +81,10 @@ LL | fn foo_with_multiple_qualified_paths(::Baz, ::Baz); | ^ expected one of 8 possible tokens | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a type, explicitly ignore the parameter name +help: explicitly ignore the parameter name | LL | fn foo_with_multiple_qualified_paths(::Baz, _: ::Baz); - | ++ + | ~~~~~~~~~~~~~~~~~~ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:22:36 diff --git a/tests/ui/suggestions/issue-64252-self-type.rs b/tests/ui/suggestions/issue-64252-self-type.rs index ea76dc8742b9b..128d5e85c22c8 100644 --- a/tests/ui/suggestions/issue-64252-self-type.rs +++ b/tests/ui/suggestions/issue-64252-self-type.rs @@ -1,11 +1,14 @@ // This test checks that a suggestion to add a `self: ` parameter name is provided // to functions where this is applicable. -pub fn foo(Box) { } //~ ERROR expected one of +pub fn foo(Box) { } +//~^ ERROR expected one of `:`, `@`, or `|`, found `<` + struct Bar; impl Bar { - fn bar(Box) { } //~ ERROR expected one of + fn bar(Box) { } + //~^ ERROR expected one of `:`, `@`, or `|`, found `<` } fn main() { } diff --git a/tests/ui/suggestions/issue-64252-self-type.stderr b/tests/ui/suggestions/issue-64252-self-type.stderr index dbef39faeadf6..c3418dab0e8af 100644 --- a/tests/ui/suggestions/issue-64252-self-type.stderr +++ b/tests/ui/suggestions/issue-64252-self-type.stderr @@ -15,7 +15,7 @@ LL | pub fn foo(_: Box) { } | ++ error: expected one of `:`, `@`, or `|`, found `<` - --> $DIR/issue-64252-self-type.rs:8:15 + --> $DIR/issue-64252-self-type.rs:10:15 | LL | fn bar(Box) { } | ^ expected one of `:`, `@`, or `|` From c6232b14fdb9d7020421746bd75468bc80b95be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 3 Aug 2023 15:39:37 +0200 Subject: [PATCH 19/19] Skip checking of `rustc_codegen_gcc` with vendoring enabled --- src/bootstrap/check.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 2c51ed5408ea0..bdefc41c9c7cd 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -307,6 +307,12 @@ impl Step for CodegenBackend { } fn run(self, builder: &Builder<'_>) { + // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved + if builder.build.config.vendor && &self.backend == "gcc" { + println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); + return; + } + let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; let backend = self.backend;