From 25d065b2d476053102b05bbd5c4650a86ddc2c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sat, 27 May 2023 15:43:26 +0800 Subject: [PATCH 01/62] Fix suggestions span for when expr is from macro expansions --- .../src/fn_ctxt/suggestions.rs | 31 ++++++---- ...10017-format-into-help-deletes-macro.fixed | 55 +++++++++++++++++ ...e-110017-format-into-help-deletes-macro.rs | 55 +++++++++++++++++ ...0017-format-into-help-deletes-macro.stderr | 59 +++++++++++++++++++ ...12007-leaked-writeln-macro-internals.fixed | 37 ++++++++++++ ...e-112007-leaked-writeln-macro-internals.rs | 37 ++++++++++++ ...2007-leaked-writeln-macro-internals.stderr | 50 ++++++++++++++++ 7 files changed, 314 insertions(+), 10 deletions(-) create mode 100644 tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed create mode 100644 tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs create mode 100644 tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr create mode 100644 tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed create mode 100644 tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs create mode 100644 tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 3a4fe334f88..6022839fe89 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -982,14 +982,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { - err.multipart_suggestion( - "you might have meant to return this value", - vec![ - (expr.span.shrink_to_lo(), "return ".to_string()), - (expr.span.shrink_to_hi(), ";".to_string()), - ], - Applicability::MaybeIncorrect, - ); + if let Some(node) = self.tcx.hir().find(fn_id) + && let Some(owner_node) = node.as_owner() + && let Some(span) = expr.span.find_ancestor_inside(owner_node.span()) + { + err.multipart_suggestion( + "you might have meant to return this value", + vec![ + (span.shrink_to_lo(), "return ".to_string()), + (span.shrink_to_hi(), ";".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } } } } @@ -1177,10 +1182,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), )) { + let mut span = expr.span; + while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite() + { + span = parent_callsite; + } + let sugg = if expr.precedence().order() >= PREC_POSTFIX { - vec![(expr.span.shrink_to_hi(), ".into()".to_owned())] + vec![(span.shrink_to_hi(), ".into()".to_owned())] } else { - vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())] + vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())] }; diag.multipart_suggestion( format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed new file mode 100644 index 00000000000..b101cf1dcf5 --- /dev/null +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed @@ -0,0 +1,55 @@ +// run-rustfix +#![allow(dead_code)] + + pub fn foo(x: &str) -> Result<(), Box> { + Err(format!("error: {x}").into()) + //~^ ERROR mismatched types + } + + macro_rules! outer { + ($x: expr) => { + inner!($x) + } + } + + macro_rules! inner { + ($x: expr) => { + format!("error: {}", $x).into() + //~^ ERROR mismatched types + } + } + + fn bar(x: &str) -> Result<(), Box> { + Err(outer!(x)) + } + + macro_rules! entire_fn_outer { + () => { + entire_fn!(); + } + } + + macro_rules! entire_fn { + () => { + pub fn baz(x: &str) -> Result<(), Box> { + Err(format!("error: {x}").into()) + //~^ ERROR mismatched types + } + } + } + + entire_fn_outer!(); + +macro_rules! nontrivial { + ($x: expr) => { + Err(format!("error: {}", $x).into()) + //~^ ERROR mismatched types + } +} + +pub fn qux(x: &str) -> Result<(), Box> { + nontrivial!(x) +} + + +fn main() {} diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs new file mode 100644 index 00000000000..cfde912d896 --- /dev/null +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs @@ -0,0 +1,55 @@ +// run-rustfix +#![allow(dead_code)] + + pub fn foo(x: &str) -> Result<(), Box> { + Err(format!("error: {x}")) + //~^ ERROR mismatched types + } + + macro_rules! outer { + ($x: expr) => { + inner!($x) + } + } + + macro_rules! inner { + ($x: expr) => { + format!("error: {}", $x) + //~^ ERROR mismatched types + } + } + + fn bar(x: &str) -> Result<(), Box> { + Err(outer!(x)) + } + + macro_rules! entire_fn_outer { + () => { + entire_fn!(); + } + } + + macro_rules! entire_fn { + () => { + pub fn baz(x: &str) -> Result<(), Box> { + Err(format!("error: {x}")) + //~^ ERROR mismatched types + } + } + } + + entire_fn_outer!(); + +macro_rules! nontrivial { + ($x: expr) => { + Err(format!("error: {}", $x)) + //~^ ERROR mismatched types + } +} + +pub fn qux(x: &str) -> Result<(), Box> { + nontrivial!(x) +} + + +fn main() {} diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr new file mode 100644 index 00000000000..e4834c0308b --- /dev/null +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr @@ -0,0 +1,59 @@ +error[E0308]: mismatched types + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:5:10 + | +LL | Err(format!("error: {x}")) + | ^^^^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` + | + = note: expected struct `Box` + found struct `String` + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) +help: call `Into::into` on this expression to convert `String` into `Box` + | +LL | Err(format!("error: {x}").into()) + | +++++++ + +error[E0308]: mismatched types + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:23:10 + | +LL | Err(outer!(x)) + | ^^^^^^^^^ expected `Box`, found `String` + | + = note: expected struct `Box` + found struct `String` + = note: this error originates in the macro `format` which comes from the expansion of the macro `outer` (in Nightly builds, run with -Z macro-backtrace for more info) +help: call `Into::into` on this expression to convert `String` into `Box` + | +LL | format!("error: {}", $x).into() + | +++++++ + +error[E0308]: mismatched types + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:41:2 + | +LL | entire_fn_outer!(); + | ^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` + | + = note: expected struct `Box` + found struct `String` + = note: this error originates in the macro `format` which comes from the expansion of the macro `entire_fn_outer` (in Nightly builds, run with -Z macro-backtrace for more info) +help: call `Into::into` on this expression to convert `String` into `Box` + | +LL | Err(format!("error: {x}").into()) + | +++++++ + +error[E0308]: mismatched types + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:51:5 + | +LL | nontrivial!(x) + | ^^^^^^^^^^^^^^ expected `Box`, found `String` + | + = note: expected struct `Box` + found struct `String` + = note: this error originates in the macro `format` which comes from the expansion of the macro `nontrivial` (in Nightly builds, run with -Z macro-backtrace for more info) +help: call `Into::into` on this expression to convert `String` into `Box` + | +LL | Err(format!("error: {}", $x).into()) + | +++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed new file mode 100644 index 00000000000..29b6b8b868f --- /dev/null +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] + +// https://github.com/rust-lang/rust/issues/112007 +fn bug_report(w: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + return writeln!(w, "but not here"); + //~^ ERROR mismatched types + }; + Ok(()) +} + +macro_rules! baz { + ($w: expr) => { + bar!($w) + } +} + +macro_rules! bar { + ($w: expr) => { + writeln!($w, "but not here") + //~^ ERROR mismatched types + } +} + +fn foo(w: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + return baz!(w); + }; + Ok(()) +} + +fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs new file mode 100644 index 00000000000..bd731e02bd1 --- /dev/null +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] + +// https://github.com/rust-lang/rust/issues/112007 +fn bug_report(w: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + writeln!(w, "but not here") + //~^ ERROR mismatched types + } + Ok(()) +} + +macro_rules! baz { + ($w: expr) => { + bar!($w) + } +} + +macro_rules! bar { + ($w: expr) => { + writeln!($w, "but not here") + //~^ ERROR mismatched types + } +} + +fn foo(w: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + baz!(w) + } + Ok(()) +} + +fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr new file mode 100644 index 00000000000..df2e06e8f3b --- /dev/null +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr @@ -0,0 +1,50 @@ +error[E0308]: mismatched types + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:9:9 + | +LL | / if true { +LL | | writeln!(w, "`;?` here ->")?; +LL | | } else { +LL | | writeln!(w, "but not here") + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>` +LL | | +LL | | } + | |_____- expected this to be `()` + | + = note: expected unit type `()` + found enum `Result<(), std::fmt::Error>` + = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using a semicolon here + | +LL | }; + | + +help: you might have meant to return this value + | +LL | return writeln!(w, "but not here"); + | ++++++ + + +error[E0308]: mismatched types + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:32:9 + | +LL | / if true { +LL | | writeln!(w, "`;?` here ->")?; +LL | | } else { +LL | | baz!(w) + | | ^^^^^^^ expected `()`, found `Result<(), Error>` +LL | | } + | |_____- expected this to be `()` + | + = note: expected unit type `()` + found enum `Result<(), std::fmt::Error>` + = note: this error originates in the macro `writeln` which comes from the expansion of the macro `baz` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using a semicolon here + | +LL | }; + | + +help: you might have meant to return this value + | +LL | return baz!(w); + | ++++++ + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 2827aa975257d03f21c75fa27a594079a9da31ba Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 21 Jun 2023 17:13:06 +0000 Subject: [PATCH 02/62] try to infer array type from slice pattern --- compiler/rustc_hir_typeck/src/pat.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8bf95d4bf9a..4785564d850 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2024,6 +2024,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_ref(self.tcx, region, mt) } + fn try_resolve_slice_ty_to_array_ty( + &self, + before: &'tcx [Pat<'tcx>], + slice: Option<&'tcx Pat<'tcx>>, + span: Span, + ) -> Option> { + if !slice.is_none() { + return None; + } + + let tcx = self.tcx; + let len = before.len(); + let ty_var_origin = + TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }; + let inner_ty = self.next_ty_var(ty_var_origin); + + Some(tcx.mk_array(inner_ty, len.try_into().unwrap())) + } + /// Type check a slice pattern. /// /// Syntactically, these look like `[pat_0, ..., pat_n]`. @@ -2044,6 +2063,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { + // If `expected` is an infer ty, we try to equate it to an array if the given pattern + // allows it. See issue #76342 + if let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice, span) && expected.is_ty_var() { + debug!(?resolved_arr_ty); + self.demand_eqtype(span, expected, resolved_arr_ty); + } + let expected = self.structurally_resolve_type(span, expected); let (element_ty, opt_slice_ty, inferred) = match *expected.kind() { // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. From e18e3761ced3695e9d7a920b223a49767dd4f1f6 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 21 Jun 2023 18:01:31 +0000 Subject: [PATCH 03/62] add test, bless tests --- tests/ui/array-slice-vec/infer_array_len.rs | 4 +- .../ui/array-slice-vec/infer_array_len.stderr | 14 ------ .../slice-pat-type-mismatches.rs | 14 +++--- .../slice-pat-type-mismatches.stderr | 18 ++++---- .../slice_destructure_fail.rs | 12 +++-- .../slice_destructure_fail.stderr | 45 +++++++++++++------ tests/ui/pattern/issue-76342.rs | 16 +++++++ 7 files changed, 74 insertions(+), 49 deletions(-) delete mode 100644 tests/ui/array-slice-vec/infer_array_len.stderr create mode 100644 tests/ui/pattern/issue-76342.rs diff --git a/tests/ui/array-slice-vec/infer_array_len.rs b/tests/ui/array-slice-vec/infer_array_len.rs index 22fe7cb8838..547c1f5727f 100644 --- a/tests/ui/array-slice-vec/infer_array_len.rs +++ b/tests/ui/array-slice-vec/infer_array_len.rs @@ -1,4 +1,4 @@ -// see issue #70529 +// check-pass struct A; impl From for [u8; 2] { @@ -13,9 +13,7 @@ impl From for [u8; 3] { } } - fn main() { let a = A; let [_, _] = a.into(); - //~^ ERROR type annotations needed } diff --git a/tests/ui/array-slice-vec/infer_array_len.stderr b/tests/ui/array-slice-vec/infer_array_len.stderr deleted file mode 100644 index c2a509a1963..00000000000 --- a/tests/ui/array-slice-vec/infer_array_len.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/infer_array_len.rs:19:9 - | -LL | let [_, _] = a.into(); - | ^^^^^^ - | -help: consider giving this pattern a type - | -LL | let [_, _]: /* Type */ = a.into(); - | ++++++++++++ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs b/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs index 521b898e7fe..310c49701ed 100644 --- a/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs +++ b/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs @@ -2,7 +2,7 @@ fn main() { match "foo".to_string() { ['f', 'o', ..] => {} //~^ ERROR expected an array or slice, found `String` - _ => { } + _ => {} }; // Note that this one works with default binding modes. @@ -15,7 +15,7 @@ fn main() { }; match [0, 1, 2] { - [0] => {}, //~ ERROR pattern requires + [0] => {} //~ ERROR pattern requires [0, 1, x @ ..] => { let a: [_; 1] = x; @@ -23,14 +23,16 @@ fn main() { [0, 1, 2, 3, x @ ..] => {} //~ ERROR pattern requires }; - match does_not_exist { //~ ERROR cannot find value `does_not_exist` in this scope - [] => {} + match does_not_exist { + //~^ ERROR cannot find value `does_not_exist` in this scope + [] => {} // ERROR cannot find value `does_not_exist` in this scope }; } fn another_fn_to_avoid_suppression() { - match Default::default() + match Default + //~^ ERROR expected value, found trait { - [] => {} //~ ERROR type annotations needed + [] => {} }; } diff --git a/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr b/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr index 70a4cbebeee..6218bffd503 100644 --- a/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr +++ b/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr @@ -4,6 +4,12 @@ error[E0425]: cannot find value `does_not_exist` in this scope LL | match does_not_exist { | ^^^^^^^^^^^^^^ not found in this scope +error[E0423]: expected value, found trait `Default` + --> $DIR/slice-pat-type-mismatches.rs:33:11 + | +LL | match Default + | ^^^^^^^ not a value + error[E0529]: expected an array or slice, found `String` --> $DIR/slice-pat-type-mismatches.rs:3:9 | @@ -13,7 +19,7 @@ LL | ['f', 'o', ..] => {} error[E0527]: pattern requires 1 element but array has 3 --> $DIR/slice-pat-type-mismatches.rs:18:9 | -LL | [0] => {}, +LL | [0] => {} | ^^^ expected 3 elements error[E0528]: pattern requires at least 4 elements but array has 3 @@ -22,13 +28,7 @@ error[E0528]: pattern requires at least 4 elements but array has 3 LL | [0, 1, 2, 3, x @ ..] => {} | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements -error[E0282]: type annotations needed - --> $DIR/slice-pat-type-mismatches.rs:34:9 - | -LL | [] => {} - | ^^ cannot infer type - error: aborting due to 5 previous errors -Some errors have detailed explanations: E0282, E0425, E0527, E0528, E0529. -For more information about an error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0423, E0425, E0527, E0528, E0529. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/destructuring-assignment/slice_destructure_fail.rs b/tests/ui/destructuring-assignment/slice_destructure_fail.rs index 33b09eb349d..e36557940ee 100644 --- a/tests/ui/destructuring-assignment/slice_destructure_fail.rs +++ b/tests/ui/destructuring-assignment/slice_destructure_fail.rs @@ -1,6 +1,10 @@ fn main() { - let (mut a, mut b); - [a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern - [a, a, b] = [1, 2]; //~ ERROR pattern requires 3 elements but array has 2 - [_] = [1, 2]; //~ ERROR pattern requires 1 element but array has 2 + let (mut a, mut b); + [a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern + [a, a, b] = [1, 2]; + //~^ ERROR pattern requires 3 elements but array has 2 + //~| ERROR mismatched types + [_] = [1, 2]; + //~^ ERROR pattern requires 1 element but array has 2 + //~| ERROR mismatched types } diff --git a/tests/ui/destructuring-assignment/slice_destructure_fail.stderr b/tests/ui/destructuring-assignment/slice_destructure_fail.stderr index 92c86febac4..e42b9695d4d 100644 --- a/tests/ui/destructuring-assignment/slice_destructure_fail.stderr +++ b/tests/ui/destructuring-assignment/slice_destructure_fail.stderr @@ -1,23 +1,42 @@ error: `..` can only be used once per slice pattern - --> $DIR/slice_destructure_fail.rs:3:14 + --> $DIR/slice_destructure_fail.rs:3:16 | -LL | [a, .., b, ..] = [0, 1]; - | -- ^^ can only be used once per slice pattern - | | - | previously used here +LL | [a, .., b, ..] = [0, 1]; + | -- ^^ can only be used once per slice pattern + | | + | previously used here + +error[E0308]: mismatched types + --> $DIR/slice_destructure_fail.rs:4:5 + | +LL | [a, a, b] = [1, 2]; + | ^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements + | + = note: expected array `[{integer}; 2]` + found array `[_; 3]` error[E0527]: pattern requires 3 elements but array has 2 - --> $DIR/slice_destructure_fail.rs:4:3 + --> $DIR/slice_destructure_fail.rs:4:5 | -LL | [a, a, b] = [1, 2]; - | ^^^^^^^^^ expected 2 elements +LL | [a, a, b] = [1, 2]; + | ^^^^^^^^^ expected 2 elements + +error[E0308]: mismatched types + --> $DIR/slice_destructure_fail.rs:7:5 + | +LL | [_] = [1, 2]; + | ^^^ expected an array with a fixed size of 2 elements, found one with 1 element + | + = note: expected array `[{integer}; 2]` + found array `[_; 1]` error[E0527]: pattern requires 1 element but array has 2 - --> $DIR/slice_destructure_fail.rs:5:3 + --> $DIR/slice_destructure_fail.rs:7:5 | -LL | [_] = [1, 2]; - | ^^^ expected 2 elements +LL | [_] = [1, 2]; + | ^^^ expected 2 elements -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0527`. +Some errors have detailed explanations: E0308, E0527. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/issue-76342.rs b/tests/ui/pattern/issue-76342.rs new file mode 100644 index 00000000000..2b3d3e522f2 --- /dev/null +++ b/tests/ui/pattern/issue-76342.rs @@ -0,0 +1,16 @@ +// check-pass +#![allow(unused_variables)] +struct Zeroes; +impl Into<[usize; 2]> for Zeroes { + fn into(self) -> [usize; 2] { [0; 2] } +} +impl Into<[usize; 3]> for Zeroes { + fn into(self) -> [usize; 3] { [0; 3] } +} +impl Into<[usize; 4]> for Zeroes { + fn into(self) -> [usize; 4] { [0; 4] } +} +fn main() { + let [a, b, c] = Zeroes.into(); // ERROR: type annotations needed + let [d, e, f]: [_; 3] = Zeroes.into(); // Works great +} From b3413c643b2b00b91ea1200ec17e49b8a161e7de Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 23 Jun 2023 12:28:19 +0000 Subject: [PATCH 04/62] only infer array type on irrefutable patterns --- compiler/rustc_hir_typeck/src/_match.rs | 2 +- compiler/rustc_hir_typeck/src/check.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 +- .../rustc_hir_typeck/src/gather_locals.rs | 31 +++- compiler/rustc_hir_typeck/src/pat.rs | 138 +++++++++++++----- 5 files changed, 138 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index f2a43cc414d..55c3cd8f4c6 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #55810: Type check patterns first so we get types for all bindings. let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span); for arm in arms { - self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut)); + self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None); } // Now typecheck the blocks. diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 53bae315d78..1fc1e5aca2b 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -89,7 +89,7 @@ pub(super) fn check_fn<'a, 'tcx>( for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { // Check the pattern. let ty_span = try { inputs_hir?.get(idx)?.span }; - fcx.check_pat_top(¶m.pat, param_ty, ty_span, None); + fcx.check_pat_top(¶m.pat, param_ty, ty_span, None, None); // Check that argument is Sized. if !params_can_be_unsized { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a9610009db1..c70de7b8b72 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,7 +1,7 @@ use crate::coercion::CoerceMany; use crate::errors::SuggestPtrNullMut; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; -use crate::gather_locals::Declaration; +use crate::gather_locals::{DeclContext, Declaration}; use crate::method::MethodCallee; use crate::TupleArgumentsFlag::*; use crate::{errors, Expectation::*}; @@ -1474,7 +1474,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type check the pattern. Override if necessary to avoid knock-on errors. - self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); + let decl_ctxt = DeclContext { has_else: decl.els.is_some(), origin: decl.origin }; + self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl_ctxt)); let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 4f45a24b216..15562d57466 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -9,6 +9,24 @@ use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; +#[derive(Debug, Copy, Clone)] +pub(super) enum DeclOrigin { + // from an `if let` expression + LetExpr, + // from `let x = ..` + LocalDecl, +} + +/// Provides context for checking patterns in declarations. More specifically this +/// allows us to infer array types if the pattern is irrefutable and allows us to infer +/// the size of the array. See issue #76342. +#[derive(Debug, Copy, Clone)] +pub(crate) struct DeclContext { + // whether we're in a let-else context + pub(super) has_else: bool, + pub(super) origin: DeclOrigin, +} + /// A declaration is an abstraction of [hir::Local] and [hir::Let]. /// /// It must have a hir_id, as this is how we connect gather_locals to the check functions. @@ -19,19 +37,28 @@ pub(super) struct Declaration<'a> { pub span: Span, pub init: Option<&'a hir::Expr<'a>>, pub els: Option<&'a hir::Block<'a>>, + pub origin: DeclOrigin, } impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { fn from(local: &'a hir::Local<'a>) -> Self { let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; - Declaration { hir_id, pat, ty, span, init, els } + Declaration { hir_id, pat, ty, span, init, els, origin: DeclOrigin::LocalDecl } } } impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { fn from(let_expr: &'a hir::Let<'a>) -> Self { let hir::Let { hir_id, pat, ty, span, init } = *let_expr; - Declaration { hir_id, pat, ty, span, init: Some(init), els: None } + Declaration { + hir_id, + pat, + ty, + span, + init: Some(init), + els: None, + origin: DeclOrigin::LetExpr, + } } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 4785564d850..5616f67f430 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1,3 +1,4 @@ +use crate::gather_locals::{DeclContext, DeclOrigin}; use crate::{errors, FnCtxt, RawTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; @@ -135,15 +136,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Otherwise, `Some(span)` represents the span of a type expression /// which originated the `expected` type. - pub fn check_pat_top( + pub(crate) fn check_pat_top( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, span: Option, origin_expr: Option<&'tcx hir::Expr<'tcx>>, + decl_ctxt: Option, ) { let info = TopInfo { expected, origin_expr, span }; - self.check_pat(pat, expected, INITIAL_BM, info); + self.check_pat(pat, expected, INITIAL_BM, info, decl_ctxt); } /// Type check the given `pat` against the `expected` type @@ -158,6 +160,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) { let path_res = match &pat.kind { PatKind::Path(qpath) => { @@ -173,33 +176,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), PatKind::Binding(ba, var_id, _, sub) => { - self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti) - } - PatKind::TupleStruct(ref qpath, subpats, ddpos) => { - self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) + self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti, decl_ctxt) } + PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct( + pat, qpath, subpats, ddpos, expected, def_bm, ti, decl_ctxt, + ), PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) } - PatKind::Struct(ref qpath, fields, has_rest_pat) => { - self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti) - } + PatKind::Struct(ref qpath, fields, has_rest_pat) => self.check_pat_struct( + pat, + qpath, + fields, + has_rest_pat, + expected, + def_bm, + ti, + decl_ctxt, + ), PatKind::Or(pats) => { for pat in pats { - self.check_pat(pat, expected, def_bm, ti); + self.check_pat(pat, expected, def_bm, ti, decl_ctxt); } expected } PatKind::Tuple(elements, ddpos) => { - self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti) + self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti, decl_ctxt) + } + PatKind::Box(inner) => { + self.check_pat_box(pat.span, inner, expected, def_bm, ti, decl_ctxt) } - PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, def_bm, ti), PatKind::Ref(inner, mutbl) => { - self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti) - } - PatKind::Slice(before, slice, after) => { - self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti) + self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti, decl_ctxt) } + PatKind::Slice(before, slice, after) => self + .check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti, decl_ctxt), }; self.write_ty(pat.hir_id, ty); @@ -582,6 +593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> Ty<'tcx> { // Determine the binding mode... let bm = match ba { @@ -620,7 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(p) = sub { - self.check_pat(p, expected, def_bm, ti); + self.check_pat(p, expected, def_bm, ti, decl_ctxt); } local_ty @@ -845,6 +857,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { @@ -853,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let err = Ty::new_error(self.tcx, guar); for field in fields { let ti = ti; - self.check_pat(field.pat, err, def_bm, ti); + self.check_pat(field.pat, err, def_bm, ti, decl_ctxt); } return err; } @@ -863,7 +876,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) { + if self.check_struct_pat_fields( + pat_ty, + &pat, + variant, + fields, + has_rest_pat, + def_bm, + ti, + decl_ctxt, + ) { pat_ty } else { Ty::new_misc_error(self.tcx) @@ -1030,11 +1052,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> Ty<'tcx> { let tcx = self.tcx; let on_error = |e| { for pat in subpats { - self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti); + self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti, decl_ctxt); } }; let report_unexpected_res = |res: Res| { @@ -1100,7 +1123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field = &variant.fields[FieldIdx::from_usize(i)]; let field_ty = self.field_ty(subpat.span, field, args); - self.check_pat(subpat, field_ty, def_bm, ti); + self.check_pat(subpat, field_ty, def_bm, ti, decl_ctxt); self.tcx.check_stability( variant.fields[FieldIdx::from_usize(i)].did, @@ -1286,6 +1309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1312,12 +1336,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti); + self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti, decl_ctxt); } Ty::new_tup_from_iter(tcx, element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, element_tys[i], def_bm, ti); + self.check_pat(elem, element_tys[i], def_bm, ti, decl_ctxt); } pat_ty } @@ -1332,6 +1356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { has_rest_pat: bool, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> bool { let tcx = self.tcx; @@ -1378,7 +1403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - self.check_pat(field.pat, field_ty, def_bm, ti); + self.check_pat(field.pat, field_ty, def_bm, ti, decl_ctxt); } let mut unmentioned_fields = variant @@ -1943,6 +1968,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { @@ -1962,7 +1988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, err) } }; - self.check_pat(inner, inner_ty, def_bm, ti); + self.check_pat(inner, inner_ty, def_bm, ti, decl_ctxt); box_ty } @@ -1975,6 +2001,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -2013,7 +2040,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, err) } }; - self.check_pat(inner, inner_ty, def_bm, ti); + self.check_pat(inner, inner_ty, def_bm, ti, decl_ctxt); ref_ty } @@ -2043,6 +2070,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(tcx.mk_array(inner_ty, len.try_into().unwrap())) } + /// Determines whether we can infer the expected type in the slice pattern to be of type array. + /// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable + /// patterns we wouldn't e.g. report ambiguity in the following situation: + /// + /// ```ignore(rust) + /// struct Zeroes; + /// const ARR: [usize; 2] = [0; 2]; + /// const ARR2: [usize; 2] = [2; 2]; + /// + /// impl Into<&'static [usize; 2]> for Zeroes { + /// fn into(self) -> &'static [usize; 2] { + /// &ARR + /// } + /// } + /// + /// impl Into<&'static [usize]> for Zeroes { + /// fn into(self) -> &'static [usize] { + /// &ARR2 + /// } + /// } + /// + /// fn main() { + /// let &[a, b]: &[usize] = Zeroes.into() else { + /// .. + /// }; + /// } + /// ``` + /// + /// If we're in an irrefutable pattern we prefer the array impl candidate given that + /// the slice impl candidate would be be rejected anyway (if no ambiguity existed). + fn decl_allows_array_type_infer(&self, decl_ctxt: Option) -> bool { + if let Some(decl_ctxt) = decl_ctxt { + !decl_ctxt.has_else && matches!(decl_ctxt.origin, DeclOrigin::LocalDecl) + } else { + false + } + } + /// Type check a slice pattern. /// /// Syntactically, these look like `[pat_0, ..., pat_n]`. @@ -2062,12 +2127,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, + decl_ctxt: Option, ) -> Ty<'tcx> { - // If `expected` is an infer ty, we try to equate it to an array if the given pattern - // allows it. See issue #76342 - if let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice, span) && expected.is_ty_var() { - debug!(?resolved_arr_ty); - self.demand_eqtype(span, expected, resolved_arr_ty); + // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it + // to an array if the given pattern allows it. See issue #76342 + if self.decl_allows_array_type_infer(decl_ctxt) && expected.is_ty_var() { + if let Some(resolved_arr_ty) = + self.try_resolve_slice_ty_to_array_ty(before, slice, span) + { + debug!(?resolved_arr_ty); + self.demand_eqtype(span, expected, resolved_arr_ty); + } } let expected = self.structurally_resolve_type(span, expected); @@ -2096,15 +2166,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check all the patterns before `slice`. for elt in before { - self.check_pat(elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, def_bm, ti, decl_ctxt); } // Type check the `slice`, if present, against its expected type. if let Some(slice) = slice { - self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti); + self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti, decl_ctxt); } // Type check the elements after `slice`, if present. for elt in after { - self.check_pat(elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, def_bm, ti, decl_ctxt); } inferred } From 39c2785aec339032632fc0c72a5c51017bfa54ae Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 30 Jun 2023 11:42:37 +0000 Subject: [PATCH 05/62] add tests for refutable patterns --- tests/ui/pattern/issue-76342.rs | 16 +++++-- tests/ui/pattern/slice-pattern-refutable.rs | 34 ++++++++++++++ .../ui/pattern/slice-pattern-refutable.stderr | 40 ++++++++++++++++ tests/ui/pattern/slice-patterns-ambiguity.rs | 47 +++++++++++++++++++ .../pattern/slice-patterns-ambiguity.stderr | 40 ++++++++++++++++ 5 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 tests/ui/pattern/slice-pattern-refutable.rs create mode 100644 tests/ui/pattern/slice-pattern-refutable.stderr create mode 100644 tests/ui/pattern/slice-patterns-ambiguity.rs create mode 100644 tests/ui/pattern/slice-patterns-ambiguity.stderr diff --git a/tests/ui/pattern/issue-76342.rs b/tests/ui/pattern/issue-76342.rs index 2b3d3e522f2..0d066a12179 100644 --- a/tests/ui/pattern/issue-76342.rs +++ b/tests/ui/pattern/issue-76342.rs @@ -2,15 +2,21 @@ #![allow(unused_variables)] struct Zeroes; impl Into<[usize; 2]> for Zeroes { - fn into(self) -> [usize; 2] { [0; 2] } + fn into(self) -> [usize; 2] { + [0; 2] + } } impl Into<[usize; 3]> for Zeroes { - fn into(self) -> [usize; 3] { [0; 3] } + fn into(self) -> [usize; 3] { + [0; 3] + } } impl Into<[usize; 4]> for Zeroes { - fn into(self) -> [usize; 4] { [0; 4] } + fn into(self) -> [usize; 4] { + [0; 4] + } } fn main() { - let [a, b, c] = Zeroes.into(); // ERROR: type annotations needed - let [d, e, f]: [_; 3] = Zeroes.into(); // Works great + let [a, b, c] = Zeroes.into(); + let [d, e, f]: [_; 3] = Zeroes.into(); } diff --git a/tests/ui/pattern/slice-pattern-refutable.rs b/tests/ui/pattern/slice-pattern-refutable.rs new file mode 100644 index 00000000000..3961da3bf53 --- /dev/null +++ b/tests/ui/pattern/slice-pattern-refutable.rs @@ -0,0 +1,34 @@ +#![allow(unused_variables)] + +struct Zeroes; + +impl Into<[usize; 3]> for Zeroes { + fn into(self) -> [usize; 3] { + [0; 3] + } +} + +fn let_else() { + let [a, b, c] = Zeroes.into() else { + //~^ ERROR type annotations needed + unreachable!(); + }; +} + +fn if_let() { + if let [a, b, c] = Zeroes.into() { + //~^ ERROR type annotations needed + unreachable!(); + } +} + +fn if_let_else() { + if let [a, b, c] = Zeroes.into() { + //~^ ERROR type annotations needed + unreachable!(); + } else { + unreachable!(); + } +} + +fn main() {} diff --git a/tests/ui/pattern/slice-pattern-refutable.stderr b/tests/ui/pattern/slice-pattern-refutable.stderr new file mode 100644 index 00000000000..cb5503bac39 --- /dev/null +++ b/tests/ui/pattern/slice-pattern-refutable.stderr @@ -0,0 +1,40 @@ +error[E0282]: type annotations needed + --> $DIR/slice-pattern-refutable.rs:12:9 + | +LL | let [a, b, c] = Zeroes.into() else { + | ^^^^^^^^^ + | +help: consider giving this pattern a type + | +LL | let [a, b, c]: /* Type */ = Zeroes.into() else { + | ++++++++++++ + +error[E0282]: type annotations needed + --> $DIR/slice-pattern-refutable.rs:19:31 + | +LL | if let [a, b, c] = Zeroes.into() { + | --------- ^^^^ + | | + | type must be known at this point + | +help: try using a fully qualified path to specify the expected types + | +LL | if let [a, b, c] = >::into(Zeroes) { + | ++++++++++++++++++++++++++ ~ + +error[E0282]: type annotations needed + --> $DIR/slice-pattern-refutable.rs:26:31 + | +LL | if let [a, b, c] = Zeroes.into() { + | --------- ^^^^ + | | + | type must be known at this point + | +help: try using a fully qualified path to specify the expected types + | +LL | if let [a, b, c] = >::into(Zeroes) { + | ++++++++++++++++++++++++++ ~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/pattern/slice-patterns-ambiguity.rs b/tests/ui/pattern/slice-patterns-ambiguity.rs new file mode 100644 index 00000000000..0fe24b0e572 --- /dev/null +++ b/tests/ui/pattern/slice-patterns-ambiguity.rs @@ -0,0 +1,47 @@ +#![allow(unused_variables)] + +struct Zeroes; + +const ARR: [usize; 2] = [0; 2]; +const ARR2: [usize; 2] = [2; 2]; + +impl Into<&'static [usize; 2]> for Zeroes { + fn into(self) -> &'static [usize; 2] { + &ARR + } +} + +impl Into<&'static [usize]> for Zeroes { + fn into(self) -> &'static [usize] { + &ARR2 + } +} + +fn let_decl() { + let &[a, b] = Zeroes.into(); +} + +fn let_else() { + let &[a, b] = Zeroes.into() else { + //~^ ERROR type annotations needed + unreachable!(); + }; +} + +fn if_let() { + if let &[a, b] = Zeroes.into() { + //~^ ERROR type annotations needed + unreachable!(); + } +} + +fn if_let_else() { + if let &[a, b] = Zeroes.into() { + //~^ ERROR type annotations needed + unreachable!(); + } else { + unreachable!(); + } +} + +fn main() {} diff --git a/tests/ui/pattern/slice-patterns-ambiguity.stderr b/tests/ui/pattern/slice-patterns-ambiguity.stderr new file mode 100644 index 00000000000..3ef99d0e2d1 --- /dev/null +++ b/tests/ui/pattern/slice-patterns-ambiguity.stderr @@ -0,0 +1,40 @@ +error[E0282]: type annotations needed for `&_` + --> $DIR/slice-patterns-ambiguity.rs:25:9 + | +LL | let &[a, b] = Zeroes.into() else { + | ^^^^^^^ + | +help: consider giving this pattern a type, where the placeholders `_` are specified + | +LL | let &[a, b]: &_ = Zeroes.into() else { + | ++++ + +error[E0282]: type annotations needed + --> $DIR/slice-patterns-ambiguity.rs:32:29 + | +LL | if let &[a, b] = Zeroes.into() { + | ------ ^^^^ + | | + | type must be known at this point + | +help: try using a fully qualified path to specify the expected types + | +LL | if let &[a, b] = >::into(Zeroes) { + | +++++++++++++++++++++++++++ ~ + +error[E0282]: type annotations needed + --> $DIR/slice-patterns-ambiguity.rs:39:29 + | +LL | if let &[a, b] = Zeroes.into() { + | ------ ^^^^ + | | + | type must be known at this point + | +help: try using a fully qualified path to specify the expected types + | +LL | if let &[a, b] = >::into(Zeroes) { + | +++++++++++++++++++++++++++ ~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0282`. From feb8bb127305f692e4b08b5b4f0eb21a0da79511 Mon Sep 17 00:00:00 2001 From: b-naber Date: Mon, 3 Jul 2023 20:37:56 +0000 Subject: [PATCH 06/62] combine arguments into PatInfo --- compiler/rustc_hir_typeck/src/pat.rs | 194 ++++++++++++++++----------- 1 file changed, 115 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 5616f67f430..fbe50966419 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -78,6 +78,13 @@ struct TopInfo<'tcx> { span: Option, } +#[derive(Copy, Clone)] +struct PatInfo<'tcx> { + binding_mode: BindingMode, + top_info: TopInfo<'tcx>, + decl_ctxt: Option, +} + impl<'tcx> FnCtxt<'_, 'tcx> { fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { let code = @@ -145,7 +152,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl_ctxt: Option, ) { let info = TopInfo { expected, origin_expr, span }; - self.check_pat(pat, expected, INITIAL_BM, info, decl_ctxt); + let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_ctxt }; + self.check_pat(pat, expected, pat_info); } /// Type check the given `pat` against the `expected` type @@ -153,15 +161,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. - #[instrument(level = "debug", skip(self, ti))] - fn check_pat( - &self, - pat: &'tcx Pat<'tcx>, - expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, - ) { + #[instrument(level = "debug", skip(self, pat_info))] + fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) { + let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; let path_res = match &pat.kind { PatKind::Path(qpath) => { Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) @@ -175,11 +177,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Wild => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), - PatKind::Binding(ba, var_id, _, sub) => { - self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti, decl_ctxt) - } + PatKind::Binding(ba, var_id, _, sub) => self.check_pat_ident( + pat, + ba, + var_id, + sub, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ), PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct( - pat, qpath, subpats, ddpos, expected, def_bm, ti, decl_ctxt, + pat, + qpath, + subpats, + ddpos, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, ), PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) @@ -190,27 +202,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields, has_rest_pat, expected, - def_bm, - ti, - decl_ctxt, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, ), PatKind::Or(pats) => { for pat in pats { - self.check_pat(pat, expected, def_bm, ti, decl_ctxt); + self.check_pat( + pat, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ); } expected } - PatKind::Tuple(elements, ddpos) => { - self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti, decl_ctxt) - } - PatKind::Box(inner) => { - self.check_pat_box(pat.span, inner, expected, def_bm, ti, decl_ctxt) - } - PatKind::Ref(inner, mutbl) => { - self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti, decl_ctxt) - } - PatKind::Slice(before, slice, after) => self - .check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti, decl_ctxt), + PatKind::Tuple(elements, ddpos) => self.check_pat_tuple( + pat.span, + elements, + ddpos, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ), + PatKind::Box(inner) => self.check_pat_box( + pat.span, + inner, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ), + PatKind::Ref(inner, mutbl) => self.check_pat_ref( + pat, + inner, + mutbl, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ), + PatKind::Slice(before, slice, after) => self.check_pat_slice( + pat.span, + before, + slice, + after, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ), }; self.write_ty(pat.hir_id, ty); @@ -591,10 +622,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_id: HirId, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { + let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + // Determine the binding mode... let bm = match ba { hir::BindingAnnotation::NONE => def_bm, @@ -632,7 +663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(p) = sub { - self.check_pat(p, expected, def_bm, ti, decl_ctxt); + self.check_pat(p, expected, PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }); } local_ty @@ -855,10 +886,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { + let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { Ok(data) => data, @@ -866,7 +897,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let err = Ty::new_error(self.tcx, guar); for field in fields { let ti = ti; - self.check_pat(field.pat, err, def_bm, ti, decl_ctxt); + self.check_pat( + field.pat, + err, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ); } return err; } @@ -882,9 +917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant, fields, has_rest_pat, - def_bm, - ti, - decl_ctxt, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, ) { pat_ty } else { @@ -1050,14 +1083,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { + let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; let tcx = self.tcx; let on_error = |e| { for pat in subpats { - self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti, decl_ctxt); + self.check_pat( + pat, + Ty::new_error(tcx, e), + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ); } }; let report_unexpected_res = |res: Res| { @@ -1123,7 +1159,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field = &variant.fields[FieldIdx::from_usize(i)]; let field_ty = self.field_ty(subpat.span, field, args); - self.check_pat(subpat, field_ty, def_bm, ti, decl_ctxt); + self.check_pat( + subpat, + field_ty, + PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + ); self.tcx.check_stability( variant.fields[FieldIdx::from_usize(i)].did, @@ -1307,9 +1347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1330,18 +1368,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); - if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) { + if let Some(mut err) = + self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) + { let reported = err.emit(); // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti, decl_ctxt); + self.check_pat(elem, Ty::new_error(tcx, reported), pat_info); } Ty::new_tup_from_iter(tcx, element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, element_tys[i], def_bm, ti, decl_ctxt); + self.check_pat(elem, element_tys[i], pat_info); } pat_ty } @@ -1354,9 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> bool { let tcx = self.tcx; @@ -1403,7 +1441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - self.check_pat(field.pat, field_ty, def_bm, ti, decl_ctxt); + self.check_pat(field.pat, field_ty, pat_info); } let mut unmentioned_fields = variant @@ -1966,9 +2004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { @@ -1980,7 +2016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: inner.span, }); let box_ty = Ty::new_box(tcx, inner_ty); - self.demand_eqtype_pat(span, expected, box_ty, ti); + self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info); (box_ty, inner_ty) } Err(guar) => { @@ -1988,7 +2024,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, err) } }; - self.check_pat(inner, inner_ty, def_bm, ti, decl_ctxt); + self.check_pat(inner, inner_ty, pat_info); box_ty } @@ -1999,9 +2035,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, mutbl: hir::Mutability, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -2023,7 +2057,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); - let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti); + let err = self.demand_eqtype_pat_diag( + pat.span, + expected, + ref_ty, + pat_info.top_info, + ); // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` @@ -2040,7 +2079,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, err) } }; - self.check_pat(inner, inner_ty, def_bm, ti, decl_ctxt); + self.check_pat(inner, inner_ty, pat_info); ref_ty } @@ -2067,10 +2106,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }; let inner_ty = self.next_ty_var(ty_var_origin); - Some(tcx.mk_array(inner_ty, len.try_into().unwrap())) + Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap())) } - /// Determines whether we can infer the expected type in the slice pattern to be of type array. + /// Used to determines whether we can infer the expected type in the slice pattern to be of type array. /// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable /// patterns we wouldn't e.g. report ambiguity in the following situation: /// @@ -2100,7 +2139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// If we're in an irrefutable pattern we prefer the array impl candidate given that /// the slice impl candidate would be be rejected anyway (if no ambiguity existed). - fn decl_allows_array_type_infer(&self, decl_ctxt: Option) -> bool { + fn pat_is_irrefutable(&self, decl_ctxt: Option) -> bool { if let Some(decl_ctxt) = decl_ctxt { !decl_ctxt.has_else && matches!(decl_ctxt.origin, DeclOrigin::LocalDecl) } else { @@ -2125,13 +2164,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - decl_ctxt: Option, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it // to an array if the given pattern allows it. See issue #76342 - if self.decl_allows_array_type_infer(decl_ctxt) && expected.is_ty_var() { + if self.pat_is_irrefutable(pat_info.decl_ctxt) && expected.is_ty_var() { if let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice, span) { @@ -2155,10 +2192,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Slice(element_ty) => (element_ty, Some(expected), expected), // The expected type must be an array or slice, but was neither, so error. _ => { - let guar = expected - .error_reported() - .err() - .unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti)); + let guar = expected.error_reported().err().unwrap_or_else(|| { + self.error_expected_array_or_slice(span, expected, pat_info.top_info) + }); let err = Ty::new_error(self.tcx, guar); (err, Some(err), err) } @@ -2166,15 +2202,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check all the patterns before `slice`. for elt in before { - self.check_pat(elt, element_ty, def_bm, ti, decl_ctxt); + self.check_pat(elt, element_ty, pat_info); } // Type check the `slice`, if present, against its expected type. if let Some(slice) = slice { - self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti, decl_ctxt); + self.check_pat(slice, opt_slice_ty.unwrap(), pat_info); } // Type check the elements after `slice`, if present. for elt in after { - self.check_pat(elt, element_ty, def_bm, ti, decl_ctxt); + self.check_pat(elt, element_ty, pat_info); } inferred } From 843e2ee5d56907be94a68d3b3b6a2057f8abaaeb Mon Sep 17 00:00:00 2001 From: b-naber Date: Mon, 3 Jul 2023 20:55:37 +0000 Subject: [PATCH 07/62] add test for nested pattern --- tests/ui/pattern/slice-patterns-nested.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/ui/pattern/slice-patterns-nested.rs diff --git a/tests/ui/pattern/slice-patterns-nested.rs b/tests/ui/pattern/slice-patterns-nested.rs new file mode 100644 index 00000000000..077e0a13954 --- /dev/null +++ b/tests/ui/pattern/slice-patterns-nested.rs @@ -0,0 +1,15 @@ +// check-pass +#![allow(unused_variables)] + +struct Zeroes; +struct Foo(T); + +impl Into<[usize; 3]> for Zeroes { + fn into(self) -> [usize; 3] { + [0; 3] + } +} + +fn main() { + let Foo([a, b, c]) = Foo(Zeroes.into()); +} From 1c217b6d8a55865535d06752a65ba2ae24f7b349 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 5 Jul 2023 20:43:37 +0000 Subject: [PATCH 08/62] move els into DeclOrigin --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 7 +- .../rustc_hir_typeck/src/gather_locals.rs | 41 +++++----- compiler/rustc_hir_typeck/src/pat.rs | 75 ++++++++++--------- 3 files changed, 60 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c70de7b8b72..2c1543ca1d5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,7 +1,7 @@ use crate::coercion::CoerceMany; use crate::errors::SuggestPtrNullMut; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; -use crate::gather_locals::{DeclContext, Declaration}; +use crate::gather_locals::Declaration; use crate::method::MethodCallee; use crate::TupleArgumentsFlag::*; use crate::{errors, Expectation::*}; @@ -1474,12 +1474,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type check the pattern. Override if necessary to avoid knock-on errors. - let decl_ctxt = DeclContext { has_else: decl.els.is_some(), origin: decl.origin }; - self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl_ctxt)); + self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin)); let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); - if let Some(blk) = decl.els { + if let Some(blk) = decl.origin.try_get_els() { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 15562d57466..b2b6ad0d101 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -9,22 +9,24 @@ use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; -#[derive(Debug, Copy, Clone)] -pub(super) enum DeclOrigin { - // from an `if let` expression - LetExpr, - // from `let x = ..` - LocalDecl, -} - /// Provides context for checking patterns in declarations. More specifically this /// allows us to infer array types if the pattern is irrefutable and allows us to infer /// the size of the array. See issue #76342. #[derive(Debug, Copy, Clone)] -pub(crate) struct DeclContext { - // whether we're in a let-else context - pub(super) has_else: bool, - pub(super) origin: DeclOrigin, +pub(super) enum DeclOrigin<'a> { + // from an `if let` expression + LetExpr, + // from `let x = ..` + LocalDecl { els: Option<&'a hir::Block<'a>> }, +} + +impl<'a> DeclOrigin<'a> { + pub(super) fn try_get_els(&self) -> Option<&'a hir::Block<'a>> { + match self { + Self::LocalDecl { els } => *els, + Self::LetExpr => None, + } + } } /// A declaration is an abstraction of [hir::Local] and [hir::Let]. @@ -36,29 +38,20 @@ pub(super) struct Declaration<'a> { pub ty: Option<&'a hir::Ty<'a>>, pub span: Span, pub init: Option<&'a hir::Expr<'a>>, - pub els: Option<&'a hir::Block<'a>>, - pub origin: DeclOrigin, + pub origin: DeclOrigin<'a>, } impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { fn from(local: &'a hir::Local<'a>) -> Self { let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; - Declaration { hir_id, pat, ty, span, init, els, origin: DeclOrigin::LocalDecl } + Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } } } } impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { fn from(let_expr: &'a hir::Let<'a>) -> Self { let hir::Let { hir_id, pat, ty, span, init } = *let_expr; - Declaration { - hir_id, - pat, - ty, - span, - init: Some(init), - els: None, - origin: DeclOrigin::LetExpr, - } + Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr } } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index fbe50966419..659223a377c 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1,4 +1,4 @@ -use crate::gather_locals::{DeclContext, DeclOrigin}; +use crate::gather_locals::DeclOrigin; use crate::{errors, FnCtxt, RawTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; @@ -79,10 +79,10 @@ struct TopInfo<'tcx> { } #[derive(Copy, Clone)] -struct PatInfo<'tcx> { +struct PatInfo<'tcx, 'a> { binding_mode: BindingMode, top_info: TopInfo<'tcx>, - decl_ctxt: Option, + decl_origin: Option>, } impl<'tcx> FnCtxt<'_, 'tcx> { @@ -149,10 +149,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, span: Option, origin_expr: Option<&'tcx hir::Expr<'tcx>>, - decl_ctxt: Option, + decl_origin: Option>, ) { let info = TopInfo { expected, origin_expr, span }; - let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_ctxt }; + let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin }; self.check_pat(pat, expected, pat_info); } @@ -162,8 +162,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] - fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) { + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; let path_res = match &pat.kind { PatKind::Path(qpath) => { Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) @@ -183,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_id, sub, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct( pat, @@ -191,7 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats, ddpos, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) @@ -202,14 +202,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields, has_rest_pat, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Or(pats) => { for pat in pats { self.check_pat( pat, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); } expected @@ -219,20 +219,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements, ddpos, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Box(inner) => self.check_pat_box( pat.span, inner, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Ref(inner, mutbl) => self.check_pat_ref( pat, inner, mutbl, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Slice(before, slice, after) => self.check_pat_slice( pat.span, @@ -240,7 +240,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice, after, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), }; @@ -622,9 +622,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_id: HirId, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; // Determine the binding mode... let bm = match ba { @@ -663,7 +663,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(p) = sub { - self.check_pat(p, expected, PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }); + self.check_pat( + p, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, + ); } local_ty @@ -886,9 +890,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { @@ -900,7 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat( field.pat, err, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); } return err; @@ -917,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant, fields, has_rest_pat, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ) { pat_ty } else { @@ -1083,16 +1087,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; let tcx = self.tcx; let on_error = |e| { for pat in subpats { self.check_pat( pat, Ty::new_error(tcx, e), - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); } }; @@ -1162,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat( subpat, field_ty, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); self.tcx.check_stability( @@ -1347,7 +1351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1394,7 +1398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> bool { let tcx = self.tcx; @@ -2004,7 +2008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { @@ -2035,7 +2039,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, mutbl: hir::Mutability, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -2139,9 +2143,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// If we're in an irrefutable pattern we prefer the array impl candidate given that /// the slice impl candidate would be be rejected anyway (if no ambiguity existed). - fn pat_is_irrefutable(&self, decl_ctxt: Option) -> bool { - if let Some(decl_ctxt) = decl_ctxt { - !decl_ctxt.has_else && matches!(decl_ctxt.origin, DeclOrigin::LocalDecl) + fn pat_is_irrefutable(&self, decl_origin: Option>) -> bool { + if let Some(decl_origin) = decl_origin { + decl_origin.try_get_els().is_none() + && matches!(decl_origin, DeclOrigin::LocalDecl { .. }) } else { false } @@ -2164,11 +2169,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it // to an array if the given pattern allows it. See issue #76342 - if self.pat_is_irrefutable(pat_info.decl_ctxt) && expected.is_ty_var() { + if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() { if let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice, span) { From 65f92a52bfee3f2d989695b80c36906404fffeca Mon Sep 17 00:00:00 2001 From: b-naber Date: Mon, 10 Jul 2023 22:11:21 +0000 Subject: [PATCH 09/62] address review --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- .../rustc_hir_typeck/src/gather_locals.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 117 +++++------------- .../slice-pat-type-mismatches.rs | 5 +- .../slice-pat-type-mismatches.stderr | 16 +-- tests/ui/pattern/issue-76342.rs | 3 + tests/ui/pattern/slice-pattern-refutable.rs | 2 + .../ui/pattern/slice-pattern-refutable.stderr | 6 +- 8 files changed, 51 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 2c1543ca1d5..70ae21d9b98 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1478,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); - if let Some(blk) = decl.origin.try_get_els() { + if let Some(blk) = decl.origin.try_get_else() { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index b2b6ad0d101..ed4c63f171c 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -21,7 +21,7 @@ pub(super) enum DeclOrigin<'a> { } impl<'a> DeclOrigin<'a> { - pub(super) fn try_get_els(&self) -> Option<&'a hir::Block<'a>> { + pub(super) fn try_get_else(&self) -> Option<&'a hir::Block<'a>> { match self { Self::LocalDecl { els } => *els, Self::LetExpr => None, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 659223a377c..8e14212fd56 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info; let path_res = match &pat.kind { PatKind::Path(qpath) => { Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) @@ -172,76 +172,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); + let pat_info = + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin }; let ty = match pat.kind { PatKind::Wild => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), - PatKind::Binding(ba, var_id, _, sub) => self.check_pat_ident( - pat, - ba, - var_id, - sub, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ), - PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct( - pat, - qpath, - subpats, - ddpos, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ), + PatKind::Binding(ba, var_id, _, sub) => { + self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info) + } + PatKind::TupleStruct(ref qpath, subpats, ddpos) => { + self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info) + } PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) } - PatKind::Struct(ref qpath, fields, has_rest_pat) => self.check_pat_struct( - pat, - qpath, - fields, - has_rest_pat, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ), + PatKind::Struct(ref qpath, fields, has_rest_pat) => { + self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info) + } PatKind::Or(pats) => { for pat in pats { - self.check_pat( - pat, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ); + self.check_pat(pat, expected, pat_info); } expected } - PatKind::Tuple(elements, ddpos) => self.check_pat_tuple( - pat.span, - elements, - ddpos, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ), - PatKind::Box(inner) => self.check_pat_box( - pat.span, - inner, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ), - PatKind::Ref(inner, mutbl) => self.check_pat_ref( - pat, - inner, - mutbl, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ), - PatKind::Slice(before, slice, after) => self.check_pat_slice( - pat.span, - before, - slice, - after, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ), + PatKind::Tuple(elements, ddpos) => { + self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info) + } + PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), + PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), + PatKind::Slice(before, slice, after) => { + self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) + } }; self.write_ty(pat.hir_id, ty); @@ -624,7 +587,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info; // Determine the binding mode... let bm = match ba { @@ -663,11 +626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(p) = sub { - self.check_pat( - p, - expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ); + self.check_pat(p, expected, pat_info); } local_ty @@ -892,37 +851,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; - // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { Ok(data) => data, Err(guar) => { let err = Ty::new_error(self.tcx, guar); for field in fields { - let ti = ti; - self.check_pat( - field.pat, - err, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ); + self.check_pat(field.pat, err, pat_info); } return err; } }; // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); + self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); // Type-check subpatterns. - if self.check_struct_pat_fields( - pat_ty, - &pat, - variant, - fields, - has_rest_pat, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, - ) { + if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, pat_info) { pat_ty } else { Ty::new_misc_error(self.tcx) @@ -2144,11 +2089,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// If we're in an irrefutable pattern we prefer the array impl candidate given that /// the slice impl candidate would be be rejected anyway (if no ambiguity existed). fn pat_is_irrefutable(&self, decl_origin: Option>) -> bool { - if let Some(decl_origin) = decl_origin { - decl_origin.try_get_els().is_none() - && matches!(decl_origin, DeclOrigin::LocalDecl { .. }) - } else { - false + match decl_origin { + Some(DeclOrigin::LocalDecl { els: None }) => true, + Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false, } } @@ -2183,6 +2126,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let expected = self.structurally_resolve_type(span, expected); + debug!(?expected); + let (element_ty, opt_slice_ty, inferred) = match *expected.kind() { // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. ty::Array(element_ty, len) => { diff --git a/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs b/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs index 310c49701ed..03a1876fdc5 100644 --- a/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs +++ b/tests/ui/array-slice-vec/slice-pat-type-mismatches.rs @@ -30,9 +30,8 @@ fn main() { } fn another_fn_to_avoid_suppression() { - match Default - //~^ ERROR expected value, found trait - { + match Default::default() { [] => {} + //~^ ERROR type annotations needed }; } diff --git a/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr b/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr index 6218bffd503..d1d042c4776 100644 --- a/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr +++ b/tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr @@ -4,12 +4,6 @@ error[E0425]: cannot find value `does_not_exist` in this scope LL | match does_not_exist { | ^^^^^^^^^^^^^^ not found in this scope -error[E0423]: expected value, found trait `Default` - --> $DIR/slice-pat-type-mismatches.rs:33:11 - | -LL | match Default - | ^^^^^^^ not a value - error[E0529]: expected an array or slice, found `String` --> $DIR/slice-pat-type-mismatches.rs:3:9 | @@ -28,7 +22,13 @@ error[E0528]: pattern requires at least 4 elements but array has 3 LL | [0, 1, 2, 3, x @ ..] => {} | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements +error[E0282]: type annotations needed + --> $DIR/slice-pat-type-mismatches.rs:34:9 + | +LL | [] => {} + | ^^ cannot infer type + error: aborting due to 5 previous errors -Some errors have detailed explanations: E0423, E0425, E0527, E0528, E0529. -For more information about an error, try `rustc --explain E0423`. +Some errors have detailed explanations: E0282, E0425, E0527, E0528, E0529. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/pattern/issue-76342.rs b/tests/ui/pattern/issue-76342.rs index 0d066a12179..e4d3218104e 100644 --- a/tests/ui/pattern/issue-76342.rs +++ b/tests/ui/pattern/issue-76342.rs @@ -1,4 +1,7 @@ // check-pass + +// Test that we infer the expected type of a pattern to an array of the given length. + #![allow(unused_variables)] struct Zeroes; impl Into<[usize; 2]> for Zeroes { diff --git a/tests/ui/pattern/slice-pattern-refutable.rs b/tests/ui/pattern/slice-pattern-refutable.rs index 3961da3bf53..1be3c6ef82d 100644 --- a/tests/ui/pattern/slice-pattern-refutable.rs +++ b/tests/ui/pattern/slice-pattern-refutable.rs @@ -1,3 +1,5 @@ +// Test that we do not infer the expected types of patterns to an array +// if we're in a refutable pattern. #![allow(unused_variables)] struct Zeroes; diff --git a/tests/ui/pattern/slice-pattern-refutable.stderr b/tests/ui/pattern/slice-pattern-refutable.stderr index cb5503bac39..df5b58d3e9c 100644 --- a/tests/ui/pattern/slice-pattern-refutable.stderr +++ b/tests/ui/pattern/slice-pattern-refutable.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/slice-pattern-refutable.rs:12:9 + --> $DIR/slice-pattern-refutable.rs:14:9 | LL | let [a, b, c] = Zeroes.into() else { | ^^^^^^^^^ @@ -10,7 +10,7 @@ LL | let [a, b, c]: /* Type */ = Zeroes.into() else { | ++++++++++++ error[E0282]: type annotations needed - --> $DIR/slice-pattern-refutable.rs:19:31 + --> $DIR/slice-pattern-refutable.rs:21:31 | LL | if let [a, b, c] = Zeroes.into() { | --------- ^^^^ @@ -23,7 +23,7 @@ LL | if let [a, b, c] = >::into(Zeroes) { | ++++++++++++++++++++++++++ ~ error[E0282]: type annotations needed - --> $DIR/slice-pattern-refutable.rs:26:31 + --> $DIR/slice-pattern-refutable.rs:28:31 | LL | if let [a, b, c] = Zeroes.into() { | --------- ^^^^ From 96af415476968d91847dde81c8ac907823b0def0 Mon Sep 17 00:00:00 2001 From: b-naber Date: Mon, 17 Jul 2023 21:58:05 +0000 Subject: [PATCH 10/62] try to structurally resolve before try_resolve_slice_ty_to_array_ty --- compiler/rustc_hir_typeck/src/pat.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8e14212fd56..e0b7407a5ee 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2114,6 +2114,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { + let expected = self.try_structurally_resolve_type(span, expected); + // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it // to an array if the given pattern allows it. See issue #76342 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() { From e1e755311a6ae8a3d15dff80851d00a8b2881d82 Mon Sep 17 00:00:00 2001 From: b-naber Date: Mon, 17 Jul 2023 21:58:37 +0000 Subject: [PATCH 11/62] add more tests --- .../slice_destructure_fail.rs | 2 - .../slice_destructure_fail.stderr | 25 +------- tests/ui/pattern/issue-76342.rs | 25 -------- tests/ui/pattern/slice-array-infer.rs | 27 ++++++++ .../ui/pattern/slice-patterns-irrefutable.rs | 62 +++++++++++++++++++ .../pattern/slice-patterns-irrefutable.stderr | 14 +++++ 6 files changed, 106 insertions(+), 49 deletions(-) delete mode 100644 tests/ui/pattern/issue-76342.rs create mode 100644 tests/ui/pattern/slice-array-infer.rs create mode 100644 tests/ui/pattern/slice-patterns-irrefutable.rs create mode 100644 tests/ui/pattern/slice-patterns-irrefutable.stderr diff --git a/tests/ui/destructuring-assignment/slice_destructure_fail.rs b/tests/ui/destructuring-assignment/slice_destructure_fail.rs index e36557940ee..e5bb50030b9 100644 --- a/tests/ui/destructuring-assignment/slice_destructure_fail.rs +++ b/tests/ui/destructuring-assignment/slice_destructure_fail.rs @@ -3,8 +3,6 @@ fn main() { [a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern [a, a, b] = [1, 2]; //~^ ERROR pattern requires 3 elements but array has 2 - //~| ERROR mismatched types [_] = [1, 2]; //~^ ERROR pattern requires 1 element but array has 2 - //~| ERROR mismatched types } diff --git a/tests/ui/destructuring-assignment/slice_destructure_fail.stderr b/tests/ui/destructuring-assignment/slice_destructure_fail.stderr index e42b9695d4d..acf44ceb184 100644 --- a/tests/ui/destructuring-assignment/slice_destructure_fail.stderr +++ b/tests/ui/destructuring-assignment/slice_destructure_fail.stderr @@ -6,37 +6,18 @@ LL | [a, .., b, ..] = [0, 1]; | | | previously used here -error[E0308]: mismatched types - --> $DIR/slice_destructure_fail.rs:4:5 - | -LL | [a, a, b] = [1, 2]; - | ^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements - | - = note: expected array `[{integer}; 2]` - found array `[_; 3]` - error[E0527]: pattern requires 3 elements but array has 2 --> $DIR/slice_destructure_fail.rs:4:5 | LL | [a, a, b] = [1, 2]; | ^^^^^^^^^ expected 2 elements -error[E0308]: mismatched types - --> $DIR/slice_destructure_fail.rs:7:5 - | -LL | [_] = [1, 2]; - | ^^^ expected an array with a fixed size of 2 elements, found one with 1 element - | - = note: expected array `[{integer}; 2]` - found array `[_; 1]` - error[E0527]: pattern requires 1 element but array has 2 - --> $DIR/slice_destructure_fail.rs:7:5 + --> $DIR/slice_destructure_fail.rs:6:5 | LL | [_] = [1, 2]; | ^^^ expected 2 elements -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0527. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0527`. diff --git a/tests/ui/pattern/issue-76342.rs b/tests/ui/pattern/issue-76342.rs deleted file mode 100644 index e4d3218104e..00000000000 --- a/tests/ui/pattern/issue-76342.rs +++ /dev/null @@ -1,25 +0,0 @@ -// check-pass - -// Test that we infer the expected type of a pattern to an array of the given length. - -#![allow(unused_variables)] -struct Zeroes; -impl Into<[usize; 2]> for Zeroes { - fn into(self) -> [usize; 2] { - [0; 2] - } -} -impl Into<[usize; 3]> for Zeroes { - fn into(self) -> [usize; 3] { - [0; 3] - } -} -impl Into<[usize; 4]> for Zeroes { - fn into(self) -> [usize; 4] { - [0; 4] - } -} -fn main() { - let [a, b, c] = Zeroes.into(); - let [d, e, f]: [_; 3] = Zeroes.into(); -} diff --git a/tests/ui/pattern/slice-array-infer.rs b/tests/ui/pattern/slice-array-infer.rs new file mode 100644 index 00000000000..f94a3dcfe0a --- /dev/null +++ b/tests/ui/pattern/slice-array-infer.rs @@ -0,0 +1,27 @@ +// check-pass + +#![allow(unused_variables)] +#![feature(generic_arg_infer)] + +struct Zeroes; +impl Into<&'static [usize; 3]> for Zeroes { + fn into(self) -> &'static [usize; 3] { + &[0; 3] + } +} +impl Into<[usize; 3]> for Zeroes { + fn into(self) -> [usize; 3] { + [0; 3] + } +} +fn main() { + let [a, b, c] = Zeroes.into(); + let [d, e, f] = >::into(Zeroes); + let &[g, h, i] = Zeroes.into(); + let [j, k, l]: [usize; _] = Zeroes.into(); + let [m, n, o]: &[usize; _] = Zeroes.into(); + + // check the binding mode of these patterns: + let _: &[usize] = &[a, b, c, g, h, i, j, k, l]; + let _: &[&usize] = &[d, e, f, m, n, o]; +} diff --git a/tests/ui/pattern/slice-patterns-irrefutable.rs b/tests/ui/pattern/slice-patterns-irrefutable.rs new file mode 100644 index 00000000000..7be02b44e43 --- /dev/null +++ b/tests/ui/pattern/slice-patterns-irrefutable.rs @@ -0,0 +1,62 @@ +// Test that we infer the expected type of a pattern to an array of the given length. + +#![allow(unused_variables)] + +use std::array::TryFromSliceError; +use std::convert::TryInto; + +struct Zeroes; +impl Into<[usize; 2]> for Zeroes { + fn into(self) -> [usize; 2] { + [0; 2] + } +} +impl Into<[usize; 3]> for Zeroes { + fn into(self) -> [usize; 3] { + [0; 3] + } +} +impl Into<[usize; 4]> for Zeroes { + fn into(self) -> [usize; 4] { + [0; 4] + } +} + +fn zeroes_into() { + let [a, b, c] = Zeroes.into(); + let [d, e, f]: [_; 3] = Zeroes.into(); +} + +fn array_try_from(x: &[usize]) -> Result { + let [a, b] = x.try_into()?; + Ok(a + b) +} + +fn default() { + let a: i32; + let b; + [a, b] = Default::default(); +} + +fn test_nested_array() { + let a: [_; 3]; + let b; + //~^ ERROR type annotations needed + [a, b] = Default::default(); +} + +struct Foo([T; 2]); + +impl Default for Foo { + fn default() -> Self { + Foo([Default::default(); 2]) + } +} + +fn field_array() { + let a: i32; + let b; + Foo([a, b]) = Default::default(); +} + +fn main() {} diff --git a/tests/ui/pattern/slice-patterns-irrefutable.stderr b/tests/ui/pattern/slice-patterns-irrefutable.stderr new file mode 100644 index 00000000000..fac99534f3e --- /dev/null +++ b/tests/ui/pattern/slice-patterns-irrefutable.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `[_; 3]` + --> $DIR/slice-patterns-irrefutable.rs:43:9 + | +LL | let b; + | ^ + | +help: consider giving `b` an explicit type, where the placeholders `_` are specified + | +LL | let b: [_; 3]; + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. From 287db04636ffefa3fdaa39fe0fdcc3cf75b60444 Mon Sep 17 00:00:00 2001 From: Catherine Date: Mon, 24 Jul 2023 04:55:47 +0000 Subject: [PATCH 12/62] Specify macro is invalid in certain contexts --- compiler/rustc_parse/messages.ftl | 6 +++ compiler/rustc_parse/src/errors.rs | 6 +++ .../rustc_parse/src/parser/diagnostics.rs | 37 +++++++++++-------- compiler/rustc_parse/src/parser/item.rs | 26 +++++++++---- compiler/rustc_parse/src/parser/pat.rs | 12 +++++- .../parser/macro/macro-expand-to-field-2.rs | 16 ++++++++ .../macro/macro-expand-to-field-2.stderr | 18 +++++++++ .../parser/macro/macro-expand-to-field-3.rs | 15 ++++++++ .../macro/macro-expand-to-field-3.stderr | 19 ++++++++++ .../ui/parser/macro/macro-expand-to-field.rs | 26 +++++++++++++ .../parser/macro/macro-expand-to-field.stderr | 29 +++++++++++++++ .../parser/macro/macro-expand-to-match-arm.rs | 15 ++++++++ .../macro/macro-expand-to-match-arm.stderr | 10 +++++ 13 files changed, 209 insertions(+), 26 deletions(-) create mode 100644 tests/ui/parser/macro/macro-expand-to-field-2.rs create mode 100644 tests/ui/parser/macro/macro-expand-to-field-2.stderr create mode 100644 tests/ui/parser/macro/macro-expand-to-field-3.rs create mode 100644 tests/ui/parser/macro/macro-expand-to-field-3.stderr create mode 100644 tests/ui/parser/macro/macro-expand-to-field.rs create mode 100644 tests/ui/parser/macro/macro-expand-to-field.stderr create mode 100644 tests/ui/parser/macro/macro-expand-to-match-arm.rs create mode 100644 tests/ui/parser/macro/macro-expand-to-match-arm.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 9787d98c1a4..7d71449122f 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -457,6 +457,12 @@ parse_loop_else = `{$loop_kind}...else` loops are not supported .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run .loop_keyword = `else` is attached to this loop +parse_macro_expands_to_adt_field = macros cannot expand to {$adt_ty} fields + +parse_macro_expands_to_enum_variant = macros cannot expand to enum variants + +parse_macro_expands_to_match_arm = macros cannot expand to match arms + parse_macro_invocation_visibility = can't qualify macro invocation with `pub` .suggestion = remove the visibility .help = try adjusting the macro to put `{$vis}` inside the invocation diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 96e1c0e3c6d..7f209c63f42 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1800,6 +1800,12 @@ pub struct UnknownPrefix<'a> { pub sugg: Option, } +#[derive(Subdiagnostic)] +#[note(parse_macro_expands_to_adt_field)] +pub struct MacroExpandsToAdtField<'a> { + pub adt_ty: &'a str, +} + #[derive(Subdiagnostic)] pub enum UnknownPrefixSugg { #[suggestion( diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c3cf6437afa..3eed3ed9e1b 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2591,6 +2591,7 @@ impl<'a> Parser<'a> { pub(crate) fn maybe_recover_unexpected_comma( &mut self, lo: Span, + is_mac_invoc: bool, rt: CommaRecoveryMode, ) -> PResult<'a, ()> { if self.token != token::Comma { @@ -2611,24 +2612,28 @@ impl<'a> Parser<'a> { let seq_span = lo.to(self.prev_token.span); let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - err.multipart_suggestion( - format!( - "try adding parentheses to match on a tuple{}", - if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." }, - ), - vec![ - (seq_span.shrink_to_lo(), "(".to_string()), - (seq_span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); - if let CommaRecoveryMode::EitherTupleOrPipe = rt { - err.span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(',', " |"), + if is_mac_invoc { + err.note(fluent::parse_macro_expands_to_match_arm); + } else { + err.multipart_suggestion( + format!( + "try adding parentheses to match on a tuple{}", + if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." }, + ), + vec![ + (seq_span.shrink_to_lo(), "(".to_string()), + (seq_span.shrink_to_hi(), ")".to_string()), + ], Applicability::MachineApplicable, ); + if let CommaRecoveryMode::EitherTupleOrPipe = rt { + err.span_suggestion( + seq_span, + "...or a vertical bar to match on multiple alternatives", + seq_snippet.replace(',', " |"), + Applicability::MachineApplicable, + ); + } } } Err(err) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1470180dea7..6ec3a1ff1a5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,8 +1,8 @@ -use crate::errors; - use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken}; +use crate::errors::{self, MacroExpandsToAdtField}; +use crate::fluent_generated as fluent; use ast::StaticItem; use rustc_ast::ast::*; use rustc_ast::ptr::P; @@ -1342,6 +1342,13 @@ impl<'a> Parser<'a> { } let ident = this.parse_field_ident("enum", vlo)?; + if this.token == token::Not { + return this.unexpected().map_err(|mut err| { + err.note(fluent::parse_macro_expands_to_enum_variant); + err + }); + } + let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) { // Parse a struct variant. let (fields, recovered) = @@ -1369,7 +1376,7 @@ impl<'a> Parser<'a> { Ok((Some(vr), TrailingToken::MaybeComma)) }, - ).map_err(|mut err|{ + ).map_err(|mut err| { err.help("enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`"); err }) @@ -1691,9 +1698,10 @@ impl<'a> Parser<'a> { Ok(a_var) } - fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> { + fn expect_field_ty_separator(&mut self, adt_ty: &str) -> PResult<'a, ()> { if let Err(mut err) = self.expect(&token::Colon) { let sm = self.sess.source_map(); + let mac_invoc = self.token.kind == token::Not; let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start()); let semi_typo = self.token.kind == token::Semi && self.look_ahead(1, |t| { @@ -1705,7 +1713,9 @@ impl<'a> Parser<'a> { _ => true, } }); - if eq_typo || semi_typo { + if mac_invoc { + err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit(); + } else if eq_typo || semi_typo { self.bump(); // Gracefully handle small typos. err.span_suggestion_short( @@ -1713,8 +1723,8 @@ impl<'a> Parser<'a> { "field names and their types are separated with `:`", ":", Applicability::MachineApplicable, - ); - err.emit(); + ) + .emit(); } else { return Err(err); } @@ -1731,7 +1741,7 @@ impl<'a> Parser<'a> { attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; - self.expect_field_ty_separator()?; + self.expect_field_ty_separator(adt_ty)?; let ty = self.parse_ty()?; if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) { self.sess.emit_err(errors::SingleColonStructType { span: self.token.span }); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 14891c45d81..b477453615d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -135,7 +135,11 @@ impl<'a> Parser<'a> { // Parse the first pattern (`p_0`). let mut first_pat = self.parse_pat_no_top_alt(expected)?; if rc == RecoverComma::Yes { - self.maybe_recover_unexpected_comma(first_pat.span, rt)?; + self.maybe_recover_unexpected_comma( + first_pat.span, + matches!(first_pat.kind, PatKind::MacCall(_)), + rt, + )?; } // If the next token is not a `|`, @@ -177,7 +181,11 @@ impl<'a> Parser<'a> { err })?; if rc == RecoverComma::Yes { - self.maybe_recover_unexpected_comma(pat.span, rt)?; + self.maybe_recover_unexpected_comma( + pat.span, + matches!(pat.kind, PatKind::MacCall(_)), + rt, + )?; } pats.push(pat); } diff --git a/tests/ui/parser/macro/macro-expand-to-field-2.rs b/tests/ui/parser/macro/macro-expand-to-field-2.rs new file mode 100644 index 00000000000..2f806bcea84 --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-field-2.rs @@ -0,0 +1,16 @@ +#![no_main] + +macro_rules! field { + ($name:ident:$type:ty) => { + $name:$type + }; +} + +enum EnumVariantField { + Named { //~ NOTE while parsing this struct + field!(oopsies:()), //~ NOTE macros cannot expand to struct fields + //~^ ERROR expected `:`, found `!` + //~^^ ERROR expected `,`, or `}`, found `(` + //~^^^ NOTE expected `:` + }, +} diff --git a/tests/ui/parser/macro/macro-expand-to-field-2.stderr b/tests/ui/parser/macro/macro-expand-to-field-2.stderr new file mode 100644 index 00000000000..8c3758173fe --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-field-2.stderr @@ -0,0 +1,18 @@ +error: expected `:`, found `!` + --> $DIR/macro-expand-to-field-2.rs:11:14 + | +LL | field!(oopsies:()), + | ^ expected `:` + | + = note: macros cannot expand to struct fields + +error: expected `,`, or `}`, found `(` + --> $DIR/macro-expand-to-field-2.rs:11:15 + | +LL | Named { + | ----- while parsing this struct +LL | field!(oopsies:()), + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/macro/macro-expand-to-field-3.rs b/tests/ui/parser/macro/macro-expand-to-field-3.rs new file mode 100644 index 00000000000..0a8b655e0dc --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-field-3.rs @@ -0,0 +1,15 @@ +#![no_main] + +macro_rules! field { + ($name:ident:$type:ty) => { + $name:$type + }; +} + +union EnumVariantField { //~ NOTE while parsing this union + A: u32, + field!(oopsies:()), //~ NOTE macros cannot expand to union fields + //~^ ERROR expected `:`, found `!` + //~^^ ERROR expected `,`, or `}`, found `(` + //~^^^ NOTE expected `:` +} diff --git a/tests/ui/parser/macro/macro-expand-to-field-3.stderr b/tests/ui/parser/macro/macro-expand-to-field-3.stderr new file mode 100644 index 00000000000..360b2bf793b --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-field-3.stderr @@ -0,0 +1,19 @@ +error: expected `:`, found `!` + --> $DIR/macro-expand-to-field-3.rs:11:10 + | +LL | field!(oopsies:()), + | ^ expected `:` + | + = note: macros cannot expand to union fields + +error: expected `,`, or `}`, found `(` + --> $DIR/macro-expand-to-field-3.rs:11:11 + | +LL | union EnumVariantField { + | ---------------- while parsing this union +LL | A: u32, +LL | field!(oopsies:()), + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/macro/macro-expand-to-field.rs b/tests/ui/parser/macro/macro-expand-to-field.rs new file mode 100644 index 00000000000..38055a3bbb2 --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-field.rs @@ -0,0 +1,26 @@ +#![no_main] + +macro_rules! field { + ($name:ident:$type:ty) => { + $name:$type + }; +} + +macro_rules! variant { + ($name:ident) => { + $name + } +} + +struct Struct { //~ NOTE while parsing this struct + field!(bar:u128), //~ NOTE macros cannot expand to struct fields + //~^ ERROR expected `:`, found `!` + //~^^ NOTE expected `:` + //~^^^ ERROR expected `,`, or `}`, found `(` +} + +enum EnumVariant { //~ NOTE while parsing this enum + variant!(whoops), //~ NOTE macros cannot expand to enum variants + //~^ ERROR unexpected token: `!` + //~^^ NOTE unexpected token after this +} diff --git a/tests/ui/parser/macro/macro-expand-to-field.stderr b/tests/ui/parser/macro/macro-expand-to-field.stderr new file mode 100644 index 00000000000..3f7fad334ec --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-field.stderr @@ -0,0 +1,29 @@ +error: expected `:`, found `!` + --> $DIR/macro-expand-to-field.rs:16:10 + | +LL | field!(bar:u128), + | ^ expected `:` + | + = note: macros cannot expand to struct fields + +error: expected `,`, or `}`, found `(` + --> $DIR/macro-expand-to-field.rs:16:11 + | +LL | struct Struct { + | ------ while parsing this struct +LL | field!(bar:u128), + | ^ + +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:23:12 + | +LL | enum EnumVariant { + | ----------- while parsing this enum +LL | variant!(whoops), + | ^ unexpected token after this + | + = note: macros cannot expand to enum variants + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs new file mode 100644 index 00000000000..043bf371902 --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs @@ -0,0 +1,15 @@ +macro_rules! arm { + ($pattern:pat => $block:block) => { + $pattern => $block + }; +} + +fn main() { + let x = Some(1); + match x { + Some(1) => {}, + arm!(None => {}), //~ NOTE macros cannot expand to match arms + //~^ ERROR unexpected `,` in pattern + _ => {}, + }; +} diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr new file mode 100644 index 00000000000..1a5f4696858 --- /dev/null +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr @@ -0,0 +1,10 @@ +error: unexpected `,` in pattern + --> $DIR/macro-expand-to-match-arm.rs:11:25 + | +LL | arm!(None => {}), + | ^ + | + = note: macros cannot expand to match arms + +error: aborting due to previous error + From dece622ee48d9744d6e64891a734e8fd25eac903 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Mon, 24 Jul 2023 17:05:10 +0000 Subject: [PATCH 13/62] Recover from some macros --- compiler/rustc_parse/src/parser/item.rs | 46 ++++++++++---- compiler/rustc_parse/src/parser/pat.rs | 6 +- .../parser/macro/macro-expand-to-field-2.rs | 16 ----- .../macro/macro-expand-to-field-2.stderr | 18 ------ .../parser/macro/macro-expand-to-field-3.rs | 15 ----- .../macro/macro-expand-to-field-3.stderr | 19 ------ .../ui/parser/macro/macro-expand-to-field.rs | 47 +++++++++++--- .../parser/macro/macro-expand-to-field.stderr | 63 +++++++++++++++---- .../parser/macro/macro-expand-to-match-arm.rs | 2 + 9 files changed, 127 insertions(+), 105 deletions(-) delete mode 100644 tests/ui/parser/macro/macro-expand-to-field-2.rs delete mode 100644 tests/ui/parser/macro/macro-expand-to-field-2.stderr delete mode 100644 tests/ui/parser/macro/macro-expand-to-field-3.rs delete mode 100644 tests/ui/parser/macro/macro-expand-to-field-3.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6ec3a1ff1a5..7b479067ecd 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1343,10 +1343,14 @@ impl<'a> Parser<'a> { let ident = this.parse_field_ident("enum", vlo)?; if this.token == token::Not { - return this.unexpected().map_err(|mut err| { - err.note(fluent::parse_macro_expands_to_enum_variant); - err - }); + if let Err(mut err) = this.unexpected::<()>() { + err.note(fluent::parse_macro_expands_to_enum_variant).emit(); + } + + this.bump(); + this.parse_delim_args()?; + + return Ok((None, TrailingToken::MaybeComma)); } let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) { @@ -1586,7 +1590,8 @@ impl<'a> Parser<'a> { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; - Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None)) + this.parse_single_struct_field(adt_ty, lo, vis, attrs) + .map(|field| (field, TrailingToken::None)) }) } @@ -1698,10 +1703,9 @@ impl<'a> Parser<'a> { Ok(a_var) } - fn expect_field_ty_separator(&mut self, adt_ty: &str) -> PResult<'a, ()> { + fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> { if let Err(mut err) = self.expect(&token::Colon) { let sm = self.sess.source_map(); - let mac_invoc = self.token.kind == token::Not; let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start()); let semi_typo = self.token.kind == token::Semi && self.look_ahead(1, |t| { @@ -1713,9 +1717,7 @@ impl<'a> Parser<'a> { _ => true, } }); - if mac_invoc { - err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit(); - } else if eq_typo || semi_typo { + if eq_typo || semi_typo { self.bump(); // Gracefully handle small typos. err.span_suggestion_short( @@ -1741,7 +1743,29 @@ impl<'a> Parser<'a> { attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; - self.expect_field_ty_separator(adt_ty)?; + // Parse the macro invocation and recover + if self.token.kind == token::Not { + if let Err(mut err) = self.unexpected::() { + err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit(); + self.bump(); + self.parse_delim_args()?; + return Ok(FieldDef { + span: DUMMY_SP, + ident: None, + vis, + id: DUMMY_NODE_ID, + ty: P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::Err, + span: DUMMY_SP, + tokens: None, + }), + attrs, + is_placeholder: false, + }); + } + } + self.expect_field_ty_separator()?; let ty = self.parse_ty()?; if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) { self.sess.emit_err(errors::SingleColonStructType { span: self.token.span }); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index b477453615d..58c00ebdea0 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -181,11 +181,7 @@ impl<'a> Parser<'a> { err })?; if rc == RecoverComma::Yes { - self.maybe_recover_unexpected_comma( - pat.span, - matches!(pat.kind, PatKind::MacCall(_)), - rt, - )?; + self.maybe_recover_unexpected_comma(pat.span, false, rt)?; } pats.push(pat); } diff --git a/tests/ui/parser/macro/macro-expand-to-field-2.rs b/tests/ui/parser/macro/macro-expand-to-field-2.rs deleted file mode 100644 index 2f806bcea84..00000000000 --- a/tests/ui/parser/macro/macro-expand-to-field-2.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_main] - -macro_rules! field { - ($name:ident:$type:ty) => { - $name:$type - }; -} - -enum EnumVariantField { - Named { //~ NOTE while parsing this struct - field!(oopsies:()), //~ NOTE macros cannot expand to struct fields - //~^ ERROR expected `:`, found `!` - //~^^ ERROR expected `,`, or `}`, found `(` - //~^^^ NOTE expected `:` - }, -} diff --git a/tests/ui/parser/macro/macro-expand-to-field-2.stderr b/tests/ui/parser/macro/macro-expand-to-field-2.stderr deleted file mode 100644 index 8c3758173fe..00000000000 --- a/tests/ui/parser/macro/macro-expand-to-field-2.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: expected `:`, found `!` - --> $DIR/macro-expand-to-field-2.rs:11:14 - | -LL | field!(oopsies:()), - | ^ expected `:` - | - = note: macros cannot expand to struct fields - -error: expected `,`, or `}`, found `(` - --> $DIR/macro-expand-to-field-2.rs:11:15 - | -LL | Named { - | ----- while parsing this struct -LL | field!(oopsies:()), - | ^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/parser/macro/macro-expand-to-field-3.rs b/tests/ui/parser/macro/macro-expand-to-field-3.rs deleted file mode 100644 index 0a8b655e0dc..00000000000 --- a/tests/ui/parser/macro/macro-expand-to-field-3.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![no_main] - -macro_rules! field { - ($name:ident:$type:ty) => { - $name:$type - }; -} - -union EnumVariantField { //~ NOTE while parsing this union - A: u32, - field!(oopsies:()), //~ NOTE macros cannot expand to union fields - //~^ ERROR expected `:`, found `!` - //~^^ ERROR expected `,`, or `}`, found `(` - //~^^^ NOTE expected `:` -} diff --git a/tests/ui/parser/macro/macro-expand-to-field-3.stderr b/tests/ui/parser/macro/macro-expand-to-field-3.stderr deleted file mode 100644 index 360b2bf793b..00000000000 --- a/tests/ui/parser/macro/macro-expand-to-field-3.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: expected `:`, found `!` - --> $DIR/macro-expand-to-field-3.rs:11:10 - | -LL | field!(oopsies:()), - | ^ expected `:` - | - = note: macros cannot expand to union fields - -error: expected `,`, or `}`, found `(` - --> $DIR/macro-expand-to-field-3.rs:11:11 - | -LL | union EnumVariantField { - | ---------------- while parsing this union -LL | A: u32, -LL | field!(oopsies:()), - | ^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/parser/macro/macro-expand-to-field.rs b/tests/ui/parser/macro/macro-expand-to-field.rs index 38055a3bbb2..fd1d408e726 100644 --- a/tests/ui/parser/macro/macro-expand-to-field.rs +++ b/tests/ui/parser/macro/macro-expand-to-field.rs @@ -12,15 +12,46 @@ macro_rules! variant { } } -struct Struct { //~ NOTE while parsing this struct +struct Struct { field!(bar:u128), //~ NOTE macros cannot expand to struct fields - //~^ ERROR expected `:`, found `!` - //~^^ NOTE expected `:` - //~^^^ ERROR expected `,`, or `}`, found `(` -} - -enum EnumVariant { //~ NOTE while parsing this enum - variant!(whoops), //~ NOTE macros cannot expand to enum variants + //~^ ERROR unexpected token: `!` + //~^^ NOTE unexpected token after this + a: u32, + b: u32, + field!(recovers:()), //~ NOTE macros cannot expand to struct fields //~^ ERROR unexpected token: `!` //~^^ NOTE unexpected token after this } + +enum EnumVariant { + variant!(whoops), //~ NOTE macros cannot expand to enum variants + //~^ ERROR unexpected token: `!` + //~^^ NOTE unexpected token after this + U32, + F64, + variant!(recovers), //~ NOTE macros cannot expand to enum variants + //~^ ERROR unexpected token: `!` + //~^^ NOTE unexpected token after this +} + +enum EnumVariantField { + Named { + field!(oopsies:()), //~ NOTE macros cannot expand to struct fields + //~^ ERROR unexpected token: `!` + //~^^ unexpected token after this + field!(oopsies2:()), //~ NOTE macros cannot expand to struct fields + //~^ ERROR unexpected token: `!` + //~^^ unexpected token after this + }, +} + +union Union { + A: u32, + field!(oopsies:()), //~ NOTE macros cannot expand to union fields + //~^ ERROR unexpected token: `!` + //~^^ unexpected token after this + B: u32, + field!(recovers:()), //~ NOTE macros cannot expand to union fields + //~^ ERROR unexpected token: `!` + //~^^ unexpected token after this +} diff --git a/tests/ui/parser/macro/macro-expand-to-field.stderr b/tests/ui/parser/macro/macro-expand-to-field.stderr index 3f7fad334ec..108b68b481f 100644 --- a/tests/ui/parser/macro/macro-expand-to-field.stderr +++ b/tests/ui/parser/macro/macro-expand-to-field.stderr @@ -1,29 +1,66 @@ -error: expected `:`, found `!` +error: unexpected token: `!` --> $DIR/macro-expand-to-field.rs:16:10 | LL | field!(bar:u128), - | ^ expected `:` + | ^ unexpected token after this | = note: macros cannot expand to struct fields -error: expected `,`, or `}`, found `(` - --> $DIR/macro-expand-to-field.rs:16:11 +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:21:10 | -LL | struct Struct { - | ------ while parsing this struct -LL | field!(bar:u128), - | ^ +LL | field!(recovers:()), + | ^ unexpected token after this + | + = note: macros cannot expand to struct fields error: unexpected token: `!` - --> $DIR/macro-expand-to-field.rs:23:12 + --> $DIR/macro-expand-to-field.rs:27:12 | -LL | enum EnumVariant { - | ----------- while parsing this enum LL | variant!(whoops), | ^ unexpected token after this | = note: macros cannot expand to enum variants - = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` -error: aborting due to 3 previous errors +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:32:12 + | +LL | variant!(recovers), + | ^ unexpected token after this + | + = note: macros cannot expand to enum variants + +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:39:14 + | +LL | field!(oopsies:()), + | ^ unexpected token after this + | + = note: macros cannot expand to struct fields + +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:42:14 + | +LL | field!(oopsies2:()), + | ^ unexpected token after this + | + = note: macros cannot expand to struct fields + +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:50:10 + | +LL | field!(oopsies:()), + | ^ unexpected token after this + | + = note: macros cannot expand to union fields + +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:54:10 + | +LL | field!(recovers:()), + | ^ unexpected token after this + | + = note: macros cannot expand to union fields + +error: aborting due to 8 previous errors diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs index 043bf371902..c176e8bbd9d 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.rs +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs @@ -10,6 +10,8 @@ fn main() { Some(1) => {}, arm!(None => {}), //~ NOTE macros cannot expand to match arms //~^ ERROR unexpected `,` in pattern + // doesn't recover + Some(2) => {}, _ => {}, }; } From 5a9af37370bc220bc395939d878c64547e3466d0 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 28 Jul 2023 11:20:11 +0000 Subject: [PATCH 14/62] address review --- tests/ui/pattern/slice-patterns-irrefutable.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/ui/pattern/slice-patterns-irrefutable.rs b/tests/ui/pattern/slice-patterns-irrefutable.rs index 7be02b44e43..bd230608eb5 100644 --- a/tests/ui/pattern/slice-patterns-irrefutable.rs +++ b/tests/ui/pattern/slice-patterns-irrefutable.rs @@ -32,7 +32,7 @@ fn array_try_from(x: &[usize]) -> Result { Ok(a + b) } -fn default() { +fn destructuring_assignment() { let a: i32; let b; [a, b] = Default::default(); @@ -45,6 +45,18 @@ fn test_nested_array() { [a, b] = Default::default(); } +fn test_nested_array_type_hint() { + let a: [_; 3]; + let b; + [a, b] = Default::default(); + let _: i32 = b[1]; +} + +fn test_working_nested_array() { + let a: i32; + [[a, _, _], _, _] = Default::default(); +} + struct Foo([T; 2]); impl Default for Foo { From 8e32dade71ad57978786537ec41c13222fd14611 Mon Sep 17 00:00:00 2001 From: bohan Date: Sun, 30 Jul 2023 15:49:33 +0800 Subject: [PATCH 15/62] 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 83d96ad8e76..aec27060fed 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 06c09960727..8ac30a6a5fe 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 e6de51a673c..6156ebec230 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 00000000000..332258b628c --- /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 00000000000..90dcdc42775 --- /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 ae8b7214a36c93b510514609f04bd576fcab9425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Sun, 30 Jul 2023 16:06:37 +0000 Subject: [PATCH 16/62] extract helper to find libLLVM's name --- src/bootstrap/llvm.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 2573c3ced36..aadfd34f506 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -491,19 +491,24 @@ impl Step for Llvm { cfg.build(); + // Helper to find the name of LLVM's shared library on darwin and linux. + let find_llvm_lib_name = |extension| { + let mut cmd = Command::new(&res.llvm_config); + let version = output(cmd.arg("--version")); + let major = version.split('.').next().unwrap(); + let lib_name = match &llvm_version_suffix { + Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"), + None => format!("libLLVM-{major}.{extension}"), + }; + lib_name + }; + // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned // libLLVM.dylib will be built. However, llvm-config will still look // for a versioned path like libLLVM-14.dylib. Manually create a symbolic // link to make llvm-config happy. if builder.llvm_link_shared() && target.contains("apple-darwin") { - let mut cmd = Command::new(&res.llvm_config); - let version = output(cmd.arg("--version")); - let major = version.split('.').next().unwrap(); - let lib_name = match llvm_version_suffix { - Some(s) => format!("libLLVM-{major}{s}.dylib"), - None => format!("libLLVM-{major}.dylib"), - }; - + let lib_name = find_llvm_lib_name("dylib"); let lib_llvm = out_dir.join("build").join("lib").join(lib_name); if !lib_llvm.exists() { t!(builder.symlink_file("libLLVM.dylib", &lib_llvm)); From 62d084517ffd815fe0e37149967d15ee57f4c8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Sun, 30 Jul 2023 16:11:10 +0000 Subject: [PATCH 17/62] strip debuginfo from LLVM's .so when applicable, on x64 linux --- src/bootstrap/llvm.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index aadfd34f506..1cab3cbf092 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -515,6 +515,32 @@ impl Step for Llvm { } } + // When building LLVM as a shared library on linux, it can contain unexpected debuginfo: + // some can come from the C++ standard library. Unless we're explicitly requesting LLVM to + // be built with debuginfo, strip it away after the fact, to make dist artifacts smaller. + // FIXME: to make things simpler for now, limit this to the host and target where we know + // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not + // cross-compiling. Expand this to other appropriate targets in the future. + if builder.llvm_link_shared() + && builder.config.llvm_optimize + && !builder.config.llvm_release_debuginfo + && target == "x86_64-unknown-linux-gnu" + && target == builder.config.build + { + // Find the name of the LLVM shared library that we just built. + let lib_name = find_llvm_lib_name("so"); + + // If the shared library exists in LLVM's `/build/lib/` or `/lib/` folders, strip its + // debuginfo. Note: `output` will propagate any errors here. + let strip_if_possible = |path: PathBuf| { + if path.exists() { + output(Command::new("strip").arg("--strip-debug").arg(path)); + } + }; + strip_if_possible(out_dir.join("lib").join(&lib_name)); + strip_if_possible(out_dir.join("build").join("lib").join(&lib_name)); + } + t!(stamp.write()); res From 67263d022dfb2c5c4cc885ed1574d16a33dd0a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 31 Jul 2023 13:20:34 +0000 Subject: [PATCH 18/62] allow `DebuginfoLevel` to be compared --- src/bootstrap/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index f3078444563..15c95dc0c60 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -50,7 +50,7 @@ pub enum DryRun { UserSelected, } -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone, Default, PartialEq, Eq)] pub enum DebuginfoLevel { #[default] None, From 4d3d96a194a50ad58764f833939726b5163df67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 31 Jul 2023 13:21:21 +0000 Subject: [PATCH 19/62] strip debuginfo from librustc_driver.so when applicable, on x64 linux --- src/bootstrap/compile.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 841288c5118..c7c1f3be2e9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -23,7 +23,7 @@ use crate::builder::crate_description; use crate::builder::Cargo; use crate::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath}; use crate::cache::{Interned, INTERNER}; -use crate::config::{LlvmLibunwind, RustcLto, TargetSelection}; +use crate::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; use crate::dist; use crate::llvm; use crate::tool::SourceType; @@ -883,16 +883,39 @@ impl Step for Rustc { compiler.host, target, ); + let stamp = librustc_stamp(builder, compiler, target); run_cargo( builder, cargo, vec![], - &librustc_stamp(builder, compiler, target), + &stamp, vec![], false, true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files. ); + // When building `librustc_driver.so` (like `libLLVM.so`) on linux, it can contain + // unexpected debuginfo from dependencies, for example from the C++ standard library used in + // our LLVM wrapper. Unless we're explicitly requesting `librustc_driver` to be built with + // debuginfo (via the debuginfo level of the executables using it): strip this debuginfo + // away after the fact. This is to make the distributed artifacts smaller, and therefore we + // only do this at stage >= 1. + // FIXME: to make things simpler for now, limit this to the host and target where we know + // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not + // cross-compiling. Expand this to other appropriate targets in the future. + if compiler.stage != 0 + && builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None + && builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None + && target == "x86_64-unknown-linux-gnu" + && target == builder.config.build + { + let target_root_dir = stamp.parent().unwrap(); + let rustc_driver = target_root_dir.join("librustc_driver.so"); + if rustc_driver.exists() { + output(Command::new("strip").arg("--strip-debug").arg(rustc_driver)); + } + } + builder.ensure(RustcLink::from_rustc( self, builder.compiler(compiler.stage, builder.config.build), From 743ae5a2eb5be808704dccb97a013add2edcca20 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 12 Jul 2023 16:17:58 +0200 Subject: [PATCH 20/62] 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 16e17fc9d6a..42748512f66 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 e3b33463ccf..b036c943f5a 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 968172693a9..5f3b5c702d7 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 7f01f2c4283..87b120fc131 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 0398c0da50f..7a08c5bda2b 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 21/62] 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 42748512f66..4897ffd0cec 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 53089294fe2..0298c24fbba 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 5f3b5c702d7..9e1d5605260 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 b036c943f5a..b2138c42224 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 7a08c5bda2b..62ce910c716 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 22/62] 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 49bdc679604..fc1fabcc0ae 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 8ec19b120d1..8257bf2947a 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 51a5976eb61..6569dad18d4 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 e420ea1d2ad..57e991e5695 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 23/62] 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 87b120fc131..600ca32ca89 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 62ce910c716..10efa8685be 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 24/62] 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 d3739733c1d..9cff8a688ff 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 acc9ca29d41..5f094ac4e7e 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 e7f27439540..e3a3f69afd9 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 25/62] 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 a180577a834..9ac8f4d725e 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 c7db0f47514aa122641e30fb5b3d1a6d76a6b4d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 2 Aug 2023 00:44:41 +0200 Subject: [PATCH 26/62] Migrate GUI colors test to original CSS color format --- tests/rustdoc-gui/pocket-menu.goml | 77 +++++++++++++----------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml index 4bdf31ecb19..404e5740305 100644 --- a/tests/rustdoc-gui/pocket-menu.goml +++ b/tests/rustdoc-gui/pocket-menu.goml @@ -29,52 +29,39 @@ click: "#help-button" assert-css: ("#help-button .popover", {"display": "none"}) assert-css: ("#settings-menu .popover", {"display": "none"}) +define-function: ( + "check-popover-colors", + (theme, border_color), + block { + set-local-storage: { + "rustdoc-theme": |theme|, + "rustdoc-use-system-theme": "false", + } + reload: + + click: "#help-button" + assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": |border_color|}, + ) + compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) + compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) + } +) + // We check the borders color now: - -// Ayu theme -set-local-storage: { - "rustdoc-theme": "ayu", - "rustdoc-use-system-theme": "false", -} -reload: - -click: "#help-button" -assert-css: ( - "#help-button .popover", - {"display": "block", "border-color": "rgb(92, 103, 115)"}, -) -compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) -compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) - -// Dark theme -set-local-storage: { - "rustdoc-theme": "dark", - "rustdoc-use-system-theme": "false", -} -reload: - -click: "#help-button" -assert-css: ( - "#help-button .popover", - {"display": "block", "border-color": "rgb(224, 224, 224)"}, -) -compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) -compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) - -// Light theme -set-local-storage: { - "rustdoc-theme": "light", - "rustdoc-use-system-theme": "false", -} -reload: - -click: "#help-button" -assert-css: ( - "#help-button .popover", - {"display": "block", "border-color": "rgb(224, 224, 224)"}, -) -compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) -compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) +call-function: ("check-popover-colors", { + "theme": "ayu", + "border_color": "#5c6773", +}) +call-function: ("check-popover-colors", { + "theme": "dark", + "border_color": "#e0e0e0", +}) +call-function: ("check-popover-colors", { + "theme": "light", + "border_color": "#e0e0e0", +}) // Opening the mobile sidebar should close the settings popover. set-window-size: (650, 600) From d9f2fdfaed8d18ede6d113426279c86d84d92445 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 31 Jul 2023 15:47:19 +1000 Subject: [PATCH 27/62] `parse_all_token_trees` cannot fail. --- compiler/rustc_parse/src/parser/mod.rs | 4 ++-- src/librustdoc/clean/render_macro_matchers.rs | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 57778d67098..b452eb6a401 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1288,12 +1288,12 @@ impl<'a> Parser<'a> { } /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF. - pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { + pub fn parse_all_token_trees(&mut self) -> Vec { let mut tts = Vec::new(); while self.token != token::Eof { tts.push(self.parse_token_tree()); } - Ok(tts) + tts } pub fn parse_tokens(&mut self) -> TokenStream { diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index ef38ca3c16c..b6120e814df 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -76,13 +76,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option reparsed_trees, - Err(diagnostic) => { - diagnostic.cancel(); - return None; - } - }; + let mut reparsed_trees = parser.parse_all_token_trees(); if reparsed_trees.len() != 1 { return None; } From db7b07aa028b65b4d85610e81fecb0d2382b8c76 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 31 Jul 2023 15:51:08 +1000 Subject: [PATCH 28/62] Inline and remove `parse_all_token_trees`. It has a single call site. --- compiler/rustc_parse/src/parser/mod.rs | 11 +---------- src/librustdoc/clean/render_macro_matchers.rs | 5 ++++- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b452eb6a401..4b23f5a6de1 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1251,7 +1251,7 @@ impl<'a> Parser<'a> { } /// Parses a single token tree from the input. - pub(crate) fn parse_token_tree(&mut self) -> TokenTree { + pub fn parse_token_tree(&mut self) -> TokenTree { match self.token.kind { token::OpenDelim(..) => { // Grab the tokens within the delimiters. @@ -1287,15 +1287,6 @@ impl<'a> Parser<'a> { } } - /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF. - pub fn parse_all_token_trees(&mut self) -> Vec { - let mut tts = Vec::new(); - while self.token != token::Eof { - tts.push(self.parse_token_tree()); - } - tts - } - pub fn parse_tokens(&mut self) -> TokenStream { let mut result = Vec::new(); loop { diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index b6120e814df..b3dc0f63e45 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -76,7 +76,10 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option Date: Mon, 31 Jul 2023 15:53:46 +1000 Subject: [PATCH 29/62] Only call `parse_token_tree` once. This code currently uses a `while` loop and gathers token trees into a vector, but it only succeeds in the case where there is a single token tree. We can instead just call `parse_token_tree` once and then look for `Eof` to detect the success case. --- src/librustdoc/clean/render_macro_matchers.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index b3dc0f63e45..66d10f2368b 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -76,14 +76,13 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option Date: Mon, 31 Jul 2023 16:15:54 +1000 Subject: [PATCH 30/62] Move `TokenCursor::num_next_calls` into `Parser` and rename it. It's more of a `Parser`-level concern than a `TokenCursor`-level concern. Also, `num_bump_calls` is a more accurate name, because it's incremented in `Parser::bump`. --- compiler/rustc_parse/src/parser/attr.rs | 6 +++--- compiler/rustc_parse/src/parser/attr_wrapper.rs | 13 ++++++------- compiler/rustc_parse/src/parser/mod.rs | 13 +++++-------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ee0abba1c17..104de47b97d 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -36,7 +36,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { let mut outer_attrs = ast::AttrVec::new(); let mut just_parsed_doc_comment = false; - let start_pos = self.token_cursor.num_next_calls; + let start_pos = self.num_bump_calls; loop { let attr = if self.check(&token::Pound) { let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span); @@ -277,7 +277,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { let mut attrs = ast::AttrVec::new(); loop { - let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap(); + let start_pos: u32 = self.num_bump_calls.try_into().unwrap(); // Only try to parse if it is an inner attribute (has `!`). let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) { Some(self.parse_attribute(InnerAttrPolicy::Permitted)?) @@ -298,7 +298,7 @@ impl<'a> Parser<'a> { None }; if let Some(attr) = attr { - let end_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap(); + let end_pos: u32 = self.num_bump_calls.try_into().unwrap(); // If we are currently capturing tokens, mark the location of this inner attribute. // If capturing ends up creating a `LazyAttrTokenStream`, we will include // this replace range with it, removing the inner attribute from the final diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 158ab2a2956..10c2066ef6c 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -213,6 +213,7 @@ impl<'a> Parser<'a> { let start_token = (self.token.clone(), self.token_spacing); let cursor_snapshot = self.token_cursor.clone(); + let start_pos = self.num_bump_calls; let has_outer_attrs = !attrs.attrs.is_empty(); let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); @@ -273,8 +274,7 @@ impl<'a> Parser<'a> { let replace_ranges_end = self.capture_state.replace_ranges.len(); - let cursor_snapshot_next_calls = cursor_snapshot.num_next_calls; - let mut end_pos = self.token_cursor.num_next_calls; + let mut end_pos = self.num_bump_calls; let mut captured_trailing = false; @@ -306,7 +306,7 @@ impl<'a> Parser<'a> { end_pos += 1; } - let num_calls = end_pos - cursor_snapshot_next_calls; + let num_calls = end_pos - start_pos; // If we have no attributes, then we will never need to // use any replace ranges. @@ -316,7 +316,7 @@ impl<'a> Parser<'a> { // Grab any replace ranges that occur *inside* the current AST node. // We will perform the actual replacement when we convert the `LazyAttrTokenStream` // to an `AttrTokenStream`. - let start_calls: u32 = cursor_snapshot_next_calls.try_into().unwrap(); + let start_calls: u32 = start_pos.try_into().unwrap(); self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] .iter() .cloned() @@ -359,8 +359,7 @@ impl<'a> Parser<'a> { // with a `FlatToken::AttrTarget`. If this AST node is inside an item // that has `#[derive]`, then this will allow us to cfg-expand this // AST node. - let start_pos = - if has_outer_attrs { attrs.start_pos } else { cursor_snapshot_next_calls }; + let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)]; assert!( @@ -464,6 +463,6 @@ mod size_asserts { use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(AttrWrapper, 16); - static_assert_size!(LazyAttrTokenStreamImpl, 120); + static_assert_size!(LazyAttrTokenStreamImpl, 112); // tidy-alphabetical-end } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4b23f5a6de1..2a1524f108a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -135,9 +135,9 @@ pub struct Parser<'a> { pub capture_cfg: bool, restrictions: Restrictions, expected_tokens: Vec, - // Important: This must only be advanced from `bump` to ensure that - // `token_cursor.num_next_calls` is updated properly. token_cursor: TokenCursor, + // The number of calls to `bump`, i.e. the position in the token stream. + num_bump_calls: usize, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. @@ -224,9 +224,6 @@ struct TokenCursor { // because it's the outermost token stream which never has delimiters. stack: Vec<(TokenTreeCursor, Delimiter, DelimSpan)>, - // Counts the number of calls to `{,inlined_}next`. - num_next_calls: usize, - // During parsing, we may sometimes need to 'unglue' a // glued token into two component tokens // (e.g. '>>' into '>' and '>), so that the parser @@ -402,9 +399,9 @@ impl<'a> Parser<'a> { token_cursor: TokenCursor { tree_cursor: stream.into_trees(), stack: Vec::new(), - num_next_calls: 0, break_last_token: false, }, + num_bump_calls: 0, unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, last_unexpected_token_span: None, @@ -1049,7 +1046,7 @@ impl<'a> Parser<'a> { // Note: destructuring here would give nicer code, but it was found in #96210 to be slower // than `.0`/`.1` access. let mut next = self.token_cursor.inlined_next(); - self.token_cursor.num_next_calls += 1; + self.num_bump_calls += 1; // We've retrieved an token from the underlying // cursor, so we no longer need to worry about // an unglued token. See `break_and_eat` for more details @@ -1446,7 +1443,7 @@ impl<'a> Parser<'a> { } pub fn approx_token_stream_pos(&self) -> usize { - self.token_cursor.num_next_calls + self.num_bump_calls } } From 6fc2c481e5a7daf1873ccc34926f1c0387979569 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 31 Jul 2023 16:36:27 +1000 Subject: [PATCH 31/62] Move `TokenCursor::break_last_token` into `Parser`. Similar to the last commit, it's more of a `Parser`-level concern than a `TokenCursor`-level concern. And the struct size reductions are nice. After this change, `TokenCursor` is as minimal as possible (two fields and two methods) which is nice. --- .../rustc_parse/src/parser/attr_wrapper.rs | 11 ++-- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 51 ++++++++----------- 3 files changed, 25 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 10c2066ef6c..5d6c574baa6 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -301,7 +301,7 @@ impl<'a> Parser<'a> { // then extend the range of captured tokens to include it, since the parser // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted // into an `AttrTokenStream`, we will create the proper token. - if self.token_cursor.break_last_token { + if self.break_last_token { assert!(!captured_trailing, "Cannot set break_last_token and have trailing token"); end_pos += 1; } @@ -331,7 +331,7 @@ impl<'a> Parser<'a> { start_token, num_calls, cursor_snapshot, - break_last_token: self.token_cursor.break_last_token, + break_last_token: self.break_last_token, replace_ranges, }); @@ -362,10 +362,7 @@ impl<'a> Parser<'a> { let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)]; - assert!( - !self.token_cursor.break_last_token, - "Should not have unglued last token with cfg attr" - ); + assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); let range: Range = (start_pos.try_into().unwrap())..(end_pos.try_into().unwrap()); self.capture_state.replace_ranges.push((range, new_tokens)); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); @@ -463,6 +460,6 @@ mod size_asserts { use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(AttrWrapper, 16); - static_assert_size!(LazyAttrTokenStreamImpl, 112); + static_assert_size!(LazyAttrTokenStreamImpl, 104); // tidy-alphabetical-end } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 55f857aa31c..975dafecb10 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1167,7 +1167,7 @@ impl<'a> Parser<'a> { DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => { assert!(suffix.is_none()); // Analogous to `Self::break_and_eat` - self.token_cursor.break_last_token = true; + self.break_last_token = true; // This might work, in cases like `1. 2`, and might not, // in cases like `offset_of!(Ty, 1.)`. It depends on what comes // after the float-like token, and therefore we have to make diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2a1524f108a..27a8af630ce 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -138,6 +138,21 @@ pub struct Parser<'a> { token_cursor: TokenCursor, // The number of calls to `bump`, i.e. the position in the token stream. num_bump_calls: usize, + // During parsing we may sometimes need to 'unglue' a glued token into two + // component tokens (e.g. '>>' into '>' and '>), so the parser can consume + // them one at a time. This process bypasses the normal capturing mechanism + // (e.g. `num_bump_calls` will not be incremented), since the 'unglued' + // tokens due not exist in the original `TokenStream`. + // + // If we end up consuming both unglued tokens, this is not an issue. We'll + // end up capturing the single 'glued' token. + // + // However, sometimes we may want to capture just the first 'unglued' + // token. For example, capturing the `Vec` in `Option>` + // requires us to unglue the trailing `>>` token. The `break_last_token` + // field is used to track this token. It gets appended to the captured + // stream when we evaluate a `LazyAttrTokenStream`. + break_last_token: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. @@ -161,7 +176,7 @@ pub struct Parser<'a> { // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure // it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Parser<'_>, 272); +rustc_data_structures::static_assert_size!(Parser<'_>, 264); /// Stores span information about a closure. #[derive(Clone)] @@ -223,29 +238,6 @@ struct TokenCursor { // tokens are in `stack[n-1]`. `stack[0]` (when present) has no delimiters // because it's the outermost token stream which never has delimiters. stack: Vec<(TokenTreeCursor, Delimiter, DelimSpan)>, - - // During parsing, we may sometimes need to 'unglue' a - // glued token into two component tokens - // (e.g. '>>' into '>' and '>), so that the parser - // can consume them one at a time. This process - // bypasses the normal capturing mechanism - // (e.g. `num_next_calls` will not be incremented), - // since the 'unglued' tokens due not exist in - // the original `TokenStream`. - // - // If we end up consuming both unglued tokens, - // then this is not an issue - we'll end up - // capturing the single 'glued' token. - // - // However, in certain circumstances, we may - // want to capture just the first 'unglued' token. - // For example, capturing the `Vec` - // in `Option>` requires us to unglue - // the trailing `>>` token. The `break_last_token` - // field is used to track this token - it gets - // appended to the captured stream when - // we evaluate a `LazyAttrTokenStream`. - break_last_token: bool, } impl TokenCursor { @@ -396,12 +388,9 @@ impl<'a> Parser<'a> { capture_cfg: false, restrictions: Restrictions::empty(), expected_tokens: Vec::new(), - token_cursor: TokenCursor { - tree_cursor: stream.into_trees(), - stack: Vec::new(), - break_last_token: false, - }, + token_cursor: TokenCursor { tree_cursor: stream.into_trees(), stack: Vec::new() }, num_bump_calls: 0, + break_last_token: false, unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, last_unexpected_token_span: None, @@ -704,7 +693,7 @@ impl<'a> Parser<'a> { // If we consume any additional tokens, then this token // is not needed (we'll capture the entire 'glued' token), // and `bump` will set this field to `None` - self.token_cursor.break_last_token = true; + self.break_last_token = true; // Use the spacing of the glued token as the spacing // of the unglued second token. self.bump_with((Token::new(second, second_span), self.token_spacing)); @@ -1050,7 +1039,7 @@ impl<'a> Parser<'a> { // We've retrieved an token from the underlying // cursor, so we no longer need to worry about // an unglued token. See `break_and_eat` for more details - self.token_cursor.break_last_token = false; + self.break_last_token = false; if next.0.span.is_dummy() { // Tweak the location for better diagnostics, but keep syntactic context intact. let fallback_span = self.token.span; From ac64a53e17097f87de8913e372a0baa99e58e31e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 31 Jul 2023 16:57:35 +1000 Subject: [PATCH 32/62] Avoid an unnecessary local variable. --- compiler/rustc_parse/src/parser/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 27a8af630ce..f0d2411a7a6 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1241,8 +1241,7 @@ impl<'a> Parser<'a> { match self.token.kind { token::OpenDelim(..) => { // Grab the tokens within the delimiters. - let tree_cursor = &self.token_cursor.tree_cursor; - let stream = tree_cursor.stream.clone(); + let stream = self.token_cursor.tree_cursor.stream.clone(); let (_, delim, span) = *self.token_cursor.stack.last().unwrap(); // Advance the token cursor through the entire delimited From ba294a816bd51526b8bf99cb21050f669b8397b0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Aug 2023 09:28:44 +1000 Subject: [PATCH 33/62] Fix an erroneous comment. The `None` variant has already been renamed `Invisible`. --- compiler/rustc_ast/src/token.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 4c920e84f86..f4ad0efa423 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -41,8 +41,6 @@ pub enum BinOpToken { /// Describes how a sequence of token trees is delimited. /// Cannot use `proc_macro::Delimiter` directly because this /// structure should implement some additional traits. -/// The `None` variant is also renamed to `Invisible` to be -/// less confusing and better convey the semantics. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Encodable, Decodable, Hash, HashStable_Generic)] pub enum Delimiter { From 47e13b51532c729fbbfc9662087fb1deba742a59 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 2 Aug 2023 15:32:23 +0200 Subject: [PATCH 34/62] Add myself to mailmap Some tool used `Samuel "Sam" Tardieu` as a full name in some of the commits imported along with clippy. --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index d526b43e4eb..601064b77d4 100644 --- a/.mailmap +++ b/.mailmap @@ -494,6 +494,7 @@ Ryan Sullivant Ryan Wiedemann S Pradeep Kumar Sam Radhakrishnan +Samuel Tardieu Scott McMurray Scott Olson Scott Olson Sean Gillespie swgillespie From 2984670cea3ca625c2a64ce2604cfe2accbe9aa2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Aug 2023 11:27:00 +0200 Subject: [PATCH 35/62] avoid 'miri' when refering to the shared interpreter --- .../rustc_const_eval/src/interpret/intrinsics.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- compiler/rustc_middle/src/mir/interpret/error.rs | 2 +- compiler/rustc_middle/src/mir/interpret/mod.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 14 +++++++------- compiler/rustc_symbol_mangling/src/v0.rs | 3 ++- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index be7c14f33c2..f97a5b3447c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -1,4 +1,4 @@ -//! Intrinsics and other functions that the miri engine executes without +//! Intrinsics and other functions that the interpreter executes without //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE //! and miri. diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 02d022a2252..ea3f3c509f5 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -91,7 +91,7 @@ impl<'tcx, Other> FnVal<'tcx, Other> { // `Memory` has to depend on the `Machine` because some of its operations // (e.g., `get`) call a `Machine` hook. pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { - /// Allocations local to this instance of the miri engine. The kind + /// Allocations local to this instance of the interpreter. The kind /// helps ensure that the same mechanism is used for allocation and /// deallocation. When an allocation is not found here, it is a /// global and looked up in the `tcx` for read access. Some machines may diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index d44dfa2172a..803dbf6cd91 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -155,7 +155,7 @@ impl<'tcx> InterpErrorInfo<'tcx> { } fn print_backtrace(backtrace: &Backtrace) { - eprintln!("\n\nAn error occurred in miri:\n{backtrace}"); + eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}"); } impl From for InterpErrorInfo<'_> { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 8b5a8d17301..b35ba9503db 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -609,7 +609,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Panics in case the `AllocId` is dangling. Since that is impossible for `AllocId`s in /// constants (as all constants must pass interning and validation that check for dangling /// ids), this function is frequently used throughout rustc, but should not be used within - /// the miri engine. + /// the interpreter. pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { match self.try_get_global_alloc(id) { Some(alloc) => alloc, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 5b678d4ba78..55b14ce1c3e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -384,7 +384,7 @@ fn collect_items_rec<'tcx>( if let Ok(alloc) = tcx.eval_static_initializer(def_id) { for &id in alloc.inner().provenance().ptrs().values() { - collect_miri(tcx, id, &mut used_items); + collect_alloc(tcx, id, &mut used_items); } } @@ -1331,8 +1331,8 @@ fn create_mono_items_for_default_impls<'tcx>( } } -/// Scans the miri alloc in order to find function calls, closures, and drop-glue. -fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) { +/// Scans the CTFE alloc in order to find function calls, closures, and drop-glue. +fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) { match tcx.global_alloc(alloc_id) { GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); @@ -1346,7 +1346,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &inner in alloc.inner().provenance().ptrs().values() { rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_miri(tcx, inner, output); + collect_alloc(tcx, inner, output); }); } } @@ -1358,7 +1358,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte } GlobalAlloc::VTable(ty, trait_ref) => { let alloc_id = tcx.vtable_allocation((ty, trait_ref)); - collect_miri(tcx, alloc_id, output) + collect_alloc(tcx, alloc_id, output) } } } @@ -1381,10 +1381,10 @@ fn collect_const_value<'tcx>( output: &mut MonoItems<'tcx>, ) { match value { - ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output), + ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_alloc(tcx, ptr.provenance, output), ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { for &id in alloc.inner().provenance().ptrs().values() { - collect_miri(tcx, id, output); + collect_alloc(tcx, id, output); } } _ => {} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 1846fda7c63..da19a3ba4fd 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -628,7 +628,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { valtree, ty ) }); - let s = std::str::from_utf8(slice).expect("non utf8 str from miri"); + let s = std::str::from_utf8(slice) + .expect("non utf8 str from MIR interpreter"); self.push("e"); From 7767cbb3b0b332fd0a46e347ea7f68f20109d768 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Aug 2023 16:14:36 +0200 Subject: [PATCH 36/62] 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 | 148 ++++++++++-------- .../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, 544 insertions(+), 408 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 2905874eec5..0b336109921 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 8cbc68d9061..3a4e2648b80 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, + 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_box_to_static, - PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_ref_to_static, + 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_box_to_mut, - PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_ref_to_mut, + PtrToMut { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_mut, + PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_validation_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, + 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 ff22d3d2d5a..d3f05af1c72 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 c1cb2f2e497..2567170f39a 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 318f93e12b5..0243fc4513a 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 eaa6c0ce2d6..231ea56e49f 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 8b5a8d17301..9f7b6b811cf 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 20861d5ffa4..5345a658803 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 8d9901807ec..6bd4be91e51 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 677a0fc5570..e95e3b18128 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 a9ac2a6dc67..2156886cd71 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 22c3dfa64fe..294bc77aa31 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 bf98d03946d..f099bc7ef7c 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 8a5424b3a6c..e087a0ebec7 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 08b98b37bd8..4c655161f79 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 eaa2d6b2794..8175fe6016a 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 eaa2d6b2794..8175fe6016a 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 5ef0d0146f2..c0ad6caecf2 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 c28a1b722ae..6db43d379d1 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 edcde13b0e0..b3df41304ac 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 | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_INT_1: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: 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 | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_INT_2: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: 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) { + 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 edcde13b0e0..b3df41304ac 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 | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_INT_1: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: 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 | MaybeUninit { uninit: () }.init, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_INT_2: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: 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) { + 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 a68d3fb17bc..adcf376b9c7 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 d1644f8a4dc..0ee1e60877f 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 f38e7916b75..02bbbf50435 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 5bff34bbe93..37b37e9659e 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 19f1748ff9c..4ee12d501e8 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 b62f903bdc2..00000000000 --- 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 ca4e0f7aa02..00000000000 --- 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 67797e6fb5a..af0f77c6767 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 4d12960b86b..5cda3c41152 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 30fd3a55e85..25ca6bc4eaa 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 00000000000..0e894ef581c --- /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 56d5a48573e..4fc304cda60 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 a93d777d286..00000000000 --- 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 50b174b850dfd227484f78c4a156a4d83a403d78 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 2 Aug 2023 13:15:35 -0700 Subject: [PATCH 37/62] Temporarily eholk from review rotation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index a180577a834..d3dce34844c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -502,7 +502,6 @@ compiler-team = [ ] compiler-team-contributors = [ "@compiler-errors", - "@eholk", "@jackh726", "@TaKO8Ki", "@WaffleLapkin", From d75ee2a6bcfc2ec9b21c0bb1ffaf34ff6b7161f1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Aug 2023 09:56:26 +1000 Subject: [PATCH 38/62] Remove `MacDelimiter`. It's the same as `Delimiter`, minus the `Invisible` variant. I'm generally in favour of using types to make impossible states unrepresentable, but this one feels very low-value, and the conversions between the two types are annoying and confusing. Look at the change in `src/tools/rustfmt/src/expr.rs` for an example: the old code converted from `MacDelimiter` to `Delimiter` and back again, for no good reason. This suggests the author was confused about the types. --- compiler/rustc_ast/src/ast.rs | 32 ++----------------- compiler/rustc_ast/src/attr/mod.rs | 14 ++++---- compiler/rustc_ast_pretty/src/pprust/state.rs | 6 ++-- compiler/rustc_builtin_macros/src/assert.rs | 5 +-- .../src/assert/context.rs | 7 ++-- .../rustc_builtin_macros/src/edition_panic.rs | 3 +- compiler/rustc_expand/src/placeholders.rs | 3 +- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 4 +-- compiler/rustc_parse/src/parser/mod.rs | 6 ++-- compiler/rustc_parse/src/parser/stmt.rs | 3 +- compiler/rustc_parse/src/validate_attr.rs | 11 ++++--- src/tools/rustfmt/src/expr.rs | 8 ++--- 13 files changed, 37 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index dd4321bea1b..2a268c2da85 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -14,7 +14,7 @@ //! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters. //! - [`EnumDef`] and [`Variant`]: Enum declaration. //! - [`MetaItemLit`] and [`LitKind`]: Literal expressions. -//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimiter`]: Macro definition and invocation. +//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`]: Macro definition and invocation. //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. @@ -1693,7 +1693,7 @@ where #[derive(Clone, Encodable, Decodable, Debug)] pub struct DelimArgs { pub dspan: DelimSpan, - pub delim: MacDelimiter, + pub delim: Delimiter, // Note: `Delimiter::Invisible` never occurs pub tokens: TokenStream, } @@ -1701,7 +1701,7 @@ impl DelimArgs { /// Whether a macro with these arguments needs a semicolon /// when used as a standalone item or statement. pub fn need_semicolon(&self) -> bool { - !matches!(self, DelimArgs { delim: MacDelimiter::Brace, .. }) + !matches!(self, DelimArgs { delim: Delimiter::Brace, .. }) } } @@ -1717,32 +1717,6 @@ where } } -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum MacDelimiter { - Parenthesis, - Bracket, - Brace, -} - -impl MacDelimiter { - pub fn to_token(self) -> Delimiter { - match self { - MacDelimiter::Parenthesis => Delimiter::Parenthesis, - MacDelimiter::Bracket => Delimiter::Bracket, - MacDelimiter::Brace => Delimiter::Brace, - } - } - - pub fn from_token(delim: Delimiter) -> Option { - match delim { - Delimiter::Parenthesis => Some(MacDelimiter::Parenthesis), - Delimiter::Bracket => Some(MacDelimiter::Bracket), - Delimiter::Brace => Some(MacDelimiter::Brace), - Delimiter::Invisible => None, - } - } -} - /// Represents a macro definition. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MacroDef { diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 8b9bb1df5dc..19a2b3017bc 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -2,7 +2,7 @@ use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute}; use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit}; -use crate::ast::{MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem, NormalAttr}; +use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr}; use crate::ast::{Path, PathSegment, DUMMY_NODE_ID}; use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter, Token}; @@ -196,7 +196,7 @@ impl AttrItem { fn meta_item_list(&self) -> Option> { match &self.args { - AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => { + AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) } AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None, @@ -402,11 +402,9 @@ impl MetaItemKind { fn from_attr_args(args: &AttrArgs) -> Option { match args { AttrArgs::Empty => Some(MetaItemKind::Word), - AttrArgs::Delimited(DelimArgs { - dspan: _, - delim: MacDelimiter::Parenthesis, - tokens, - }) => MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List), + AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => { + MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List) + } AttrArgs::Delimited(..) => None, AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind { ExprKind::Lit(token_lit) => { @@ -578,7 +576,7 @@ pub fn mk_attr_nested_word( let path = Path::from_ident(outer_ident); let attr_args = AttrArgs::Delimited(DelimArgs { dspan: DelimSpan::from_single(span), - delim: MacDelimiter::Parenthesis, + delim: Delimiter::Parenthesis, tokens: inner_tokens, }); mk_attr(g, style, path, attr_args, span) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 59239b49edd..068b255e9f2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -476,7 +476,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere Some(MacHeader::Path(&item.path)), false, None, - delim.to_token(), + *delim, tokens, true, span, @@ -640,7 +640,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere Some(MacHeader::Keyword(kw)), has_bang, Some(*ident), - macro_def.body.delim.to_token(), + macro_def.body.delim, ¯o_def.body.tokens.clone(), true, sp, @@ -1240,7 +1240,7 @@ impl<'a> State<'a> { Some(MacHeader::Path(&m.path)), true, None, - m.args.delim.to_token(), + m.args.delim, &m.args.tokens.clone(), true, m.span(), diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index ab4ea9c8c20..3e90ae6907f 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -4,8 +4,9 @@ use crate::edition_panic::use_panic_2021; use crate::errors; use rustc_ast::ptr::P; use rustc_ast::token; +use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, MacDelimiter, Path, PathSegment, UnOp}; +use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp}; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; @@ -58,7 +59,7 @@ pub fn expand_assert<'cx>( path: panic_path(), args: P(DelimArgs { dspan: DelimSpan::from_single(call_site_span), - delim: MacDelimiter::Parenthesis, + delim: Delimiter::Parenthesis, tokens, }), })), diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 902c1e40c75..cbf115127cf 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,9 +1,10 @@ use rustc_ast::{ ptr::P, token, + token::Delimiter, tokenstream::{DelimSpan, TokenStream, TokenTree}, - BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MacDelimiter, MethodCall, - Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, + BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability, + Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -179,7 +180,7 @@ impl<'cx, 'a> Context<'cx, 'a> { path: panic_path, args: P(DelimArgs { dspan: DelimSpan::from_single(self.span), - delim: MacDelimiter::Parenthesis, + delim: Delimiter::Parenthesis, tokens: initial.into_iter().chain(captures).collect::(), }), })), diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index ef0db23ff2f..1e1dadab480 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -1,4 +1,5 @@ use rustc_ast::ptr::P; +use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::*; use rustc_expand::base::*; @@ -60,7 +61,7 @@ fn expand<'cx>( }, args: P(DelimArgs { dspan: DelimSpan::from_single(sp), - delim: MacDelimiter::Parenthesis, + delim: Delimiter::Parenthesis, tokens: tts, }), })), diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index e9af688ee2b..82cac229284 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -2,6 +2,7 @@ use crate::expand::{AstFragment, AstFragmentKind}; use rustc_ast as ast; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; +use rustc_ast::token::Delimiter; use rustc_data_structures::fx::FxHashMap; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::Ident; @@ -18,7 +19,7 @@ pub fn placeholder( path: ast::Path { span: DUMMY_SP, segments: ThinVec::new(), tokens: None }, args: P(ast::DelimArgs { dspan: ast::tokenstream::DelimSpan::dummy(), - delim: ast::MacDelimiter::Parenthesis, + delim: Delimiter::Parenthesis, tokens: ast::tokenstream::TokenStream::new(Vec::new()), }), }) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 975dafecb10..dc3b131e7f2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2599,7 +2599,7 @@ impl<'a> Parser<'a> { // Recover from missing expression in `for` loop if matches!(expr.kind, ExprKind::Block(..)) - && !matches!(self.token.kind, token::OpenDelim(token::Delimiter::Brace)) + && !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace)) && self.may_recover() { self.sess diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1301ed3e388..e9cc858c8c5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -9,12 +9,12 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; +use rustc_ast::MacCall; use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID}; use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; -use rustc_ast::{MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; use rustc_errors::{ struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, @@ -1968,7 +1968,7 @@ impl<'a> Parser<'a> { let arrow = TokenTree::token_alone(token::FatArrow, pspan.between(bspan)); // `=>` let tokens = TokenStream::new(vec![params, arrow, body]); let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); - P(DelimArgs { dspan, delim: MacDelimiter::Brace, tokens }) + P(DelimArgs { dspan, delim: Delimiter::Brace, tokens }) } else { return self.unexpected(); }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f0d2411a7a6..c5b46b809b1 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -25,7 +25,7 @@ use rustc_ast::util::case::Case; use rustc_ast::AttrId; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern}; -use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit}; +use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit}; use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -1216,12 +1216,10 @@ impl<'a> Parser<'a> { || self.check(&token::OpenDelim(Delimiter::Brace)); delimited.then(|| { - // We've confirmed above that there is a delimiter so unwrapping is OK. let TokenTree::Delimited(dspan, delim, tokens) = self.parse_token_tree() else { unreachable!() }; - - DelimArgs { dspan, delim: MacDelimiter::from_token(delim).unwrap(), tokens } + DelimArgs { dspan, delim, tokens } }) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1cdf2efa764..12c267351b9 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -193,10 +193,9 @@ impl<'a> Parser<'a> { /// At this point, the `!` token after the path has already been eaten. fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> { let args = self.parse_delim_args()?; - let delim = args.delim.to_token(); let hi = self.prev_token.span; - let style = match delim { + let style = match args.delim { Delimiter::Brace => MacStmtStyle::Braces, _ => MacStmtStyle::NoBraces, }; diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 2011083019c..f7396598220 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -2,9 +2,10 @@ use crate::{errors, parse_in}; +use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::MetaItemKind; -use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MacDelimiter, MetaItem}; +use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; @@ -84,8 +85,8 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } -pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) { - if let ast::MacDelimiter::Parenthesis = delim { +pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: Delimiter) { + if let Delimiter::Parenthesis = delim { return; } sess.emit_err(errors::MetaBadDelim { @@ -94,8 +95,8 @@ pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimit }); } -pub fn check_cfg_attr_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) { - if let ast::MacDelimiter::Parenthesis = delim { +pub fn check_cfg_attr_bad_delim(sess: &ParseSess, span: DelimSpan, delim: Delimiter) { + if let Delimiter::Parenthesis = delim { return; } sess.emit_err(errors::CfgAttrBadDelim { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 5b1b4fbd491..739afb4e0ac 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1382,12 +1382,8 @@ pub(crate) fn can_be_overflowed_expr( || (context.use_block_indent() && args_len == 1) } ast::ExprKind::MacCall(ref mac) => { - match ( - rustc_ast::ast::MacDelimiter::from_token(mac.args.delim.to_token()), - context.config.overflow_delimited_expr(), - ) { - (Some(ast::MacDelimiter::Bracket), true) - | (Some(ast::MacDelimiter::Brace), true) => true, + match (mac.args.delim, context.config.overflow_delimited_expr()) { + (Delimiter::Bracket, true) | (Delimiter::Brace, true) => true, _ => context.use_block_indent() && args_len == 1, } } From bbd69e4a4c27f2407326a71a4eb37de694a72b87 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Wed, 2 Aug 2023 23:59:30 +0000 Subject: [PATCH 39/62] Add test for enum with fields --- compiler/rustc_parse/src/parser/item.rs | 7 +-- .../ui/parser/macro/macro-expand-to-field.rs | 57 ++++++++++++------- .../parser/macro/macro-expand-to-field.stderr | 22 ++++--- .../parser/macro/macro-expand-to-match-arm.rs | 5 +- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 7b479067ecd..2f1d377585d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1754,12 +1754,7 @@ impl<'a> Parser<'a> { ident: None, vis, id: DUMMY_NODE_ID, - ty: P(Ty { - id: DUMMY_NODE_ID, - kind: TyKind::Err, - span: DUMMY_SP, - tokens: None, - }), + ty: self.mk_ty(DUMMY_SP, TyKind::Err), attrs, is_placeholder: false, }); diff --git a/tests/ui/parser/macro/macro-expand-to-field.rs b/tests/ui/parser/macro/macro-expand-to-field.rs index fd1d408e726..155872f7a5d 100644 --- a/tests/ui/parser/macro/macro-expand-to-field.rs +++ b/tests/ui/parser/macro/macro-expand-to-field.rs @@ -1,4 +1,4 @@ -#![no_main] +// compile-flags: --crate-type=lib macro_rules! field { ($name:ident:$type:ty) => { @@ -13,9 +13,10 @@ macro_rules! variant { } struct Struct { - field!(bar:u128), //~ NOTE macros cannot expand to struct fields - //~^ ERROR unexpected token: `!` - //~^^ NOTE unexpected token after this + field!(bar:u128), + //~^ NOTE macros cannot expand to struct fields + //~| ERROR unexpected token: `!` + //~| NOTE unexpected token after this a: u32, b: u32, field!(recovers:()), //~ NOTE macros cannot expand to struct fields @@ -24,34 +25,46 @@ struct Struct { } enum EnumVariant { - variant!(whoops), //~ NOTE macros cannot expand to enum variants - //~^ ERROR unexpected token: `!` - //~^^ NOTE unexpected token after this + variant!(whoops), + //~^ NOTE macros cannot expand to enum variants + //~| ERROR unexpected token: `!` + //~| NOTE unexpected token after this U32, F64, - variant!(recovers), //~ NOTE macros cannot expand to enum variants - //~^ ERROR unexpected token: `!` - //~^^ NOTE unexpected token after this + variant!(recovers), + //~^ NOTE macros cannot expand to enum variants + //~| ERROR unexpected token: `!` + //~| NOTE unexpected token after this + Data { + field!(x:u32), + //~^ NOTE macros cannot expand to struct fields + //~| ERROR unexpected token: `!` + //~| NOTE unexpected token after this + } } enum EnumVariantField { Named { - field!(oopsies:()), //~ NOTE macros cannot expand to struct fields - //~^ ERROR unexpected token: `!` - //~^^ unexpected token after this - field!(oopsies2:()), //~ NOTE macros cannot expand to struct fields - //~^ ERROR unexpected token: `!` - //~^^ unexpected token after this + field!(oopsies:()), + //~^ NOTE macros cannot expand to struct fields + //~| ERROR unexpected token: `!` + //~| unexpected token after this + field!(oopsies2:()), + //~^ NOTE macros cannot expand to struct fields + //~| ERROR unexpected token: `!` + //~| unexpected token after this }, } union Union { A: u32, - field!(oopsies:()), //~ NOTE macros cannot expand to union fields - //~^ ERROR unexpected token: `!` - //~^^ unexpected token after this + field!(oopsies:()), + //~^ NOTE macros cannot expand to union fields + //~| ERROR unexpected token: `!` + //~| unexpected token after this B: u32, - field!(recovers:()), //~ NOTE macros cannot expand to union fields - //~^ ERROR unexpected token: `!` - //~^^ unexpected token after this + field!(recovers:()), + //~^ NOTE macros cannot expand to union fields + //~| ERROR unexpected token: `!` + //~| unexpected token after this } diff --git a/tests/ui/parser/macro/macro-expand-to-field.stderr b/tests/ui/parser/macro/macro-expand-to-field.stderr index 108b68b481f..adcd032f5c0 100644 --- a/tests/ui/parser/macro/macro-expand-to-field.stderr +++ b/tests/ui/parser/macro/macro-expand-to-field.stderr @@ -7,7 +7,7 @@ LL | field!(bar:u128), = note: macros cannot expand to struct fields error: unexpected token: `!` - --> $DIR/macro-expand-to-field.rs:21:10 + --> $DIR/macro-expand-to-field.rs:22:10 | LL | field!(recovers:()), | ^ unexpected token after this @@ -15,7 +15,7 @@ LL | field!(recovers:()), = note: macros cannot expand to struct fields error: unexpected token: `!` - --> $DIR/macro-expand-to-field.rs:27:12 + --> $DIR/macro-expand-to-field.rs:28:12 | LL | variant!(whoops), | ^ unexpected token after this @@ -23,7 +23,7 @@ LL | variant!(whoops), = note: macros cannot expand to enum variants error: unexpected token: `!` - --> $DIR/macro-expand-to-field.rs:32:12 + --> $DIR/macro-expand-to-field.rs:34:12 | LL | variant!(recovers), | ^ unexpected token after this @@ -33,13 +33,21 @@ LL | variant!(recovers), error: unexpected token: `!` --> $DIR/macro-expand-to-field.rs:39:14 | +LL | field!(x:u32), + | ^ unexpected token after this + | + = note: macros cannot expand to struct fields + +error: unexpected token: `!` + --> $DIR/macro-expand-to-field.rs:48:14 + | LL | field!(oopsies:()), | ^ unexpected token after this | = note: macros cannot expand to struct fields error: unexpected token: `!` - --> $DIR/macro-expand-to-field.rs:42:14 + --> $DIR/macro-expand-to-field.rs:52:14 | LL | field!(oopsies2:()), | ^ unexpected token after this @@ -47,7 +55,7 @@ LL | field!(oopsies2:()), = note: macros cannot expand to struct fields error: unexpected token: `!` - --> $DIR/macro-expand-to-field.rs:50:10 + --> $DIR/macro-expand-to-field.rs:61:10 | LL | field!(oopsies:()), | ^ unexpected token after this @@ -55,12 +63,12 @@ LL | field!(oopsies:()), = note: macros cannot expand to union fields error: unexpected token: `!` - --> $DIR/macro-expand-to-field.rs:54:10 + --> $DIR/macro-expand-to-field.rs:66:10 | LL | field!(recovers:()), | ^ unexpected token after this | = note: macros cannot expand to union fields -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs index c176e8bbd9d..39d1d065ed9 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.rs +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs @@ -8,8 +8,9 @@ fn main() { let x = Some(1); match x { Some(1) => {}, - arm!(None => {}), //~ NOTE macros cannot expand to match arms - //~^ ERROR unexpected `,` in pattern + arm!(None => {}), + //~^ NOTE macros cannot expand to match arms + //~| ERROR unexpected `,` in pattern // doesn't recover Some(2) => {}, _ => {}, From 6ae2677d72f1bc2b239ecfbfa1bb8d672fbfd211 Mon Sep 17 00:00:00 2001 From: Taras Tsugrii Date: Wed, 2 Aug 2023 20:51:16 -0700 Subject: [PATCH 40/62] [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 259f4238654..4811bb2c354 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 6868b93cf57c8397ef2df0dae5f5b584352cff97 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Aug 2023 04:15:01 +0000 Subject: [PATCH 41/62] No need for Expectation::IsLast --- compiler/rustc_hir_typeck/src/_match.rs | 16 +++------------- compiler/rustc_hir_typeck/src/expectation.rs | 9 ++------- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 15 ++++----------- 3 files changed, 9 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index d5f03a6aaed..f32327ad21b 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -137,13 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(&arm.body), arm_ty, Some(&mut |err| { - self.suggest_removing_semicolon_for_coerce( - err, - expr, - orig_expected, - arm_ty, - prior_arm, - ) + self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm) }), false, ); @@ -181,7 +175,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, diag: &mut Diagnostic, expr: &hir::Expr<'tcx>, - expectation: Expectation<'tcx>, arm_ty: Ty<'tcx>, prior_arm: Option<(Option, Ty<'tcx>, Span)>, ) { @@ -195,7 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::ExprKind::Block(block, _) = body.value.kind else { return; }; - let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. }) = + let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), span: semi_span, .. }) = block.innermost_block().stmts.last() else { return; @@ -212,9 +205,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else { return; }; - let Expectation::IsLast(stmt) = expectation else { - return; - }; let can_coerce_to_return_ty = match self.ret_coercion.as_ref() { Some(ret_coercion) => { @@ -231,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi()); + let semi_span = expr.span.shrink_to_hi().with_hi(semi_span.hi()); let mut ret_span: MultiSpan = semi_span.into(); ret_span.push_span_label( expr.span, diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 4f086cf597d..35e5fb769a5 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -21,8 +21,6 @@ pub enum Expectation<'tcx> { /// This rvalue expression will be wrapped in `&` or `Box` and coerced /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. ExpectRvalueLikeUnsized(Ty<'tcx>), - - IsLast(Span), } impl<'a, 'tcx> Expectation<'tcx> { @@ -88,13 +86,12 @@ impl<'a, 'tcx> Expectation<'tcx> { ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)), ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)), ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)), - IsLast(sp) => IsLast(sp), } } pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self.resolve(fcx) { - NoExpectation | IsLast(_) => None, + NoExpectation => None, ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), } } @@ -106,9 +103,7 @@ impl<'a, 'tcx> Expectation<'tcx> { pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self { ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)), - NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => { - None - } + NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e3d97b41980..302b5fd8d9c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1485,7 +1485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_decl(local.into()); } - pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { // Don't do all the complex logic below for `DeclItem`. match stmt.kind { hir::StmtKind::Item(..) => return, @@ -1512,14 +1512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } hir::StmtKind::Semi(ref expr) => { - // All of this is equivalent to calling `check_expr`, but it is inlined out here - // in order to capture the fact that this `match` is the last statement in its - // function. This is done for better suggestions to remove the `;`. - let expectation = match expr.kind { - hir::ExprKind::Match(..) if is_last => IsLast(stmt.span), - _ => NoExpectation, - }; - self.check_expr_with_expectation(expr, expectation); + self.check_expr(expr); } } @@ -1570,8 +1563,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { - for (pos, s) in blk.stmts.iter().enumerate() { - self.check_stmt(s, blk.stmts.len() - 1 == pos); + for s in blk.stmts { + self.check_stmt(s); } // check the tail expression **without** holding the From f3589a723d057aa40c618b81efde224ebc426a43 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Aug 2023 04:19:42 +0000 Subject: [PATCH 42/62] Inline check_expr_meets_expectation_or_error --- compiler/rustc_hir_typeck/src/expr.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index eb6359ed72f..5662072208e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -68,20 +68,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_expr_has_type_or_error( &self, expr: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - extend_err: impl FnMut(&mut Diagnostic), + expected_ty: Ty<'tcx>, + extend_err: impl FnOnce(&mut Diagnostic), ) -> Ty<'tcx> { - self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err) - } - - fn check_expr_meets_expectation_or_error( - &self, - expr: &'tcx hir::Expr<'tcx>, - expected: Expectation<'tcx>, - mut extend_err: impl FnMut(&mut Diagnostic), - ) -> Ty<'tcx> { - let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); - let mut ty = self.check_expr_with_expectation(expr, expected); + let mut ty = self.check_expr_with_expectation(expr, ExpectHasType(expected_ty)); // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. From a63bb245939d116bf22a1e7c15a14a751b177a4f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Aug 2023 04:21:18 +0000 Subject: [PATCH 43/62] Inline one usage of check_expr_eq_type --- compiler/rustc_hir_typeck/src/expr.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 5662072208e..401eff3d5c8 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -60,11 +60,6 @@ use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - fn check_expr_eq_type(&self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>) { - let ty = self.check_expr_with_hint(expr, expected); - self.demand_eqtype(expr.span, expected, ty); - } - pub fn check_expr_has_type_or_error( &self, expr: &'tcx hir::Expr<'tcx>, @@ -331,9 +326,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), ExprKind::Type(e, t) => { - let ty = self.to_ty_saving_user_provided_ty(&t); - self.check_expr_eq_type(&e, ty); - ty + let ascribed_ty = self.to_ty_saving_user_provided_ty(&t); + let ty = self.check_expr_with_hint(e, ascribed_ty); + self.demand_eqtype(e.span, ascribed_ty, ty); + ascribed_ty } ExprKind::If(cond, then_expr, opt_else_expr) => { self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected) From aa41c9873762af552369822da5361c5bdfe438cb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Aug 2023 04:33:07 +0000 Subject: [PATCH 44/62] Make Option<&dyn FnMut> into impl FnOnce --- compiler/rustc_hir_typeck/src/_match.rs | 6 ++---- compiler/rustc_hir_typeck/src/coercion.rs | 12 +++++------- compiler/rustc_hir_typeck/src/expr.rs | 6 +++--- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +++--- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index f32327ad21b..c2d987a95cf 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -136,9 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(&arm.body), arm_ty, - Some(&mut |err| { - self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm) - }), + |err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm), false, ); @@ -269,7 +267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.coerce_forced_unit( self, &cause, - &mut |err| { + |err| { if let Some((span, msg)) = &ret_reason { err.span_label(*span, msg.clone()); } else if let ExprKind::Block(block, _) = &then_expr.kind diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 4fdfc51bc86..fa6bad84376 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1418,7 +1418,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expression: &'tcx hir::Expr<'tcx>, expression_ty: Ty<'tcx>, ) { - self.coerce_inner(fcx, cause, Some(expression), expression_ty, None, false) + self.coerce_inner(fcx, cause, Some(expression), expression_ty, |_| {}, false) } /// Indicates that one of the inputs is a "forced unit". This @@ -1437,7 +1437,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, - augment_error: &mut dyn FnMut(&mut Diagnostic), + augment_error: impl FnOnce(&mut Diagnostic), label_unit_as_expected: bool, ) { self.coerce_inner( @@ -1445,7 +1445,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { cause, None, Ty::new_unit(fcx.tcx), - Some(augment_error), + augment_error, label_unit_as_expected, ) } @@ -1460,7 +1460,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { cause: &ObligationCause<'tcx>, expression: Option<&'tcx hir::Expr<'tcx>>, mut expression_ty: Ty<'tcx>, - augment_error: Option<&mut dyn FnMut(&mut Diagnostic)>, + augment_error: impl FnOnce(&mut Diagnostic), label_expression_as_expected: bool, ) { // Incorporate whatever type inference information we have @@ -1639,9 +1639,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } - if let Some(augment_error) = augment_error { - augment_error(&mut err); - } + augment_error(&mut err); let is_insufficiently_polymorphic = matches!(coercion_error, TypeError::RegionsInsufficientlyPolymorphic(..)); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 401eff3d5c8..80d7cc57edb 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -652,7 +652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce_forced_unit( self, &cause, - &mut |mut err| { + |mut err| { self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); @@ -748,7 +748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.coerce_forced_unit( self, &cause, - &mut |db| { + |db| { let span = fn_decl.output.span(); if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { db.span_label( @@ -760,7 +760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true, ); } else { - coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); + coercion.coerce_forced_unit(self, &cause, |_| (), true); } } self.tcx.types.never diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 302b5fd8d9c..94c54197294 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1587,9 +1587,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(tail_expr), tail_expr_ty, - Some(&mut |diag: &mut Diagnostic| { + |diag| { self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic); - }), + }, false, ); } else { @@ -1626,7 +1626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce_forced_unit( self, &self.misc(sp), - &mut |err| { + |err| { if let Some(expected_ty) = expected.only_has_type(self) { if blk.stmts.is_empty() && blk.expr.is_none() { self.suggest_boxing_when_appropriate( From 2195fa6a9bad1e95511875c93c34b55fe7ae55fa Mon Sep 17 00:00:00 2001 From: bohan Date: Thu, 3 Aug 2023 16:44:02 +0800 Subject: [PATCH 45/62] 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 25077f9bb97..7739cf1ee05 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 00000000000..c522793dbcb --- /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 00000000000..39e35f733a1 --- /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 46/62] Also lint on cast/cast_mut and ptr::from_mut/ptr::from_ref --- compiler/rustc_lint/src/ptr_nulls.rs | 54 +++++++++++------ 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, 122 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index b2138c42224..64b86fec46b 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; - } - if !had_at_least_one_cast { - None - } 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 }) + 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 { - None - } + return 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 { + None } } diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs index 8babb68585d..43b9767db16 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 600ca32ca89..e677ea3094d 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 10efa8685be..525d96c4919 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 ee519532f69610e208fc61a68537aa662c3e8d16 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 3 Aug 2023 10:57:11 +0200 Subject: [PATCH 47/62] 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 4897ffd0cec..027a10de9bb 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 9e1d5605260..c0a8d078dc4 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 64b86fec46b..02aff91032f 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 d0ed4edfc65645cd7377ad501f1a2c5c8b5385b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 3 Aug 2023 11:25:25 +0200 Subject: [PATCH 48/62] Migrate GUI colors test to original CSS color format --- tests/rustdoc-gui/sidebar-source-code-display.goml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 33210c9fdc9..88546ed2549 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -141,7 +141,7 @@ call-function: ("check-colors", { "theme": "ayu", "color": "#c5c5c5", "color_hover": "#ffb44c", - "background": "rgb(20, 25, 31)", + "background": "#14191f", "background_hover": "#14191f", "background_toggle": "rgba(0, 0, 0, 0)", "background_toggle_hover": "rgba(70, 70, 70, 0.33)", From 4457ef2c6db2aa65aeaba084d2d85f3355595f5a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 10 Jul 2023 13:03:48 +0000 Subject: [PATCH 49/62] Forbid old-style `simd_shuffleN` intrinsics --- .../src/intrinsics/simd.rs | 54 +-- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 427 ++++++++++-------- compiler/rustc_codegen_llvm/src/intrinsic.rs | 34 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- .../src/error_codes/E0439.md | 2 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 14 - .../src/lower_intrinsics.rs | 2 +- tests/incremental/issue-61530.rs | 6 +- .../simd/intrinsic/generic-elements-pass.rs | 22 +- tests/ui/simd/intrinsic/generic-elements.rs | 22 +- .../ui/simd/intrinsic/generic-elements.stderr | 74 +-- .../simd/intrinsic/inlining-issue67557-ice.rs | 4 +- .../ui/simd/intrinsic/inlining-issue67557.rs | 6 +- tests/ui/simd/shuffle-not-out-of-bounds.rs | 31 +- .../ui/simd/shuffle-not-out-of-bounds.stderr | 50 +- tests/ui/simd/shuffle.rs | 3 +- 16 files changed, 384 insertions(+), 371 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index d1c29f24ab9..9863e40b5b7 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -117,8 +117,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - // simd_shuffle32(x: T, y: T, idx: [u32; 32]) -> U - _ if intrinsic.as_str().starts_with("simd_shuffle") => { + // simd_shuffle(x: T, y: T, idx: I) -> U + sym::simd_shuffle => { let (x, y, idx) = match args { [x, y, idx] => (x, y, idx), _ => { @@ -133,36 +133,26 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer. - // If there is no suffix, use the index array length. - let n: u16 = if intrinsic == sym::simd_shuffle { - // Make sure this is actually an array, since typeck only checks the length-suffixed - // version of this intrinsic. - let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx)); - match idx_ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len - .try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) - .unwrap_or_else(|| { - span_bug!(span, "could not evaluate shuffle index array length") - }) - .try_into() - .unwrap(), - _ => { - fx.tcx.sess.span_err( - span, - format!( - "simd_shuffle index must be an array of `u32`, got `{}`", - idx_ty, - ), - ); - // Prevent verifier error - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - return; - } + // Make sure this is actually an array, since typeck only checks the length-suffixed + // version of this intrinsic. + let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx)); + let n: u16 = match idx_ty.kind() { + ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len + .try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) + .unwrap_or_else(|| { + span_bug!(span, "could not evaluate shuffle index array length") + }) + .try_into() + .unwrap(), + _ => { + fx.tcx.sess.span_err( + span, + format!("simd_shuffle index must be an array of `u32`, got `{}`", idx_ty), + ); + // Prevent verifier error + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + return; } - } else { - // FIXME remove this case - intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap() }; assert_eq!(x.layout(), y.layout()); @@ -179,7 +169,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let indexes = { use rustc_middle::mir::interpret::*; let idx_const = crate::constant::mir_operand_get_const_val(fx, idx) - .expect("simd_shuffle* idx not const"); + .expect("simd_shuffle idx not const"); let idx_bytes = match idx_const { ConstValue::ByRef { alloc, offset } => { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index f27de867d36..85d3e7234a0 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -1,11 +1,11 @@ -#[cfg(feature="master")] -use gccjit::{ComparisonOp, UnaryOp}; use gccjit::ToRValue; use gccjit::{BinaryOp, RValue, Type}; +#[cfg(feature = "master")] +use gccjit::{ComparisonOp, UnaryOp}; use rustc_codegen_ssa::base::compare_simd_types; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -#[cfg(feature="master")] +#[cfg(feature = "master")] use rustc_codegen_ssa::errors::ExpectedPointerMutability; use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::OperandRef; @@ -19,7 +19,7 @@ use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::Align; use crate::builder::Builder; -#[cfg(feature="master")] +#[cfg(feature = "master")] use crate::context::CodegenCx; pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( @@ -57,7 +57,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let arg_tys = sig.inputs(); if name == sym::simd_select_bitmask { - require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }); + require_simd!( + arg_tys[1], + InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] } + ); let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let expected_int_bits = (len.max(8) - 1).next_power_of_two(); @@ -95,7 +98,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // NOTE: since the arguments can be vectors of floats, make sure the mask is a vector of // integer. let mask_element_type = bx.type_ix(arg1_element_type.get_size() as u64 * 8); - let vector_mask_type = bx.context.new_vector_type(mask_element_type, arg1_vector_type.get_num_units() as u64); + let vector_mask_type = + bx.context.new_vector_type(mask_element_type, arg1_vector_type.get_num_units() as u64); let mut elements = vec![]; let one = bx.context.new_rvalue_one(mask.get_type()); @@ -149,38 +153,24 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // compare them as equal, so bitcast. // FIXME(antoyo): allow comparing vector types as equal in libgccjit. let arg2 = bx.context.new_bitcast(None, args[1].immediate(), arg1.get_type()); - return Ok(compare_simd_types( - bx, - arg1, - arg2, - in_elem, - llret_ty, - cmp_op, - )); + return Ok(compare_simd_types(bx, arg1, arg2, in_elem, llret_ty, cmp_op)); } - if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") { - let n: u64 = if stripped.is_empty() { - // Make sure this is actually an array, since typeck only checks the length-suffixed - // version of this intrinsic. - match args[2].layout.ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { - len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( - || span_bug!(span, "could not evaluate shuffle index array length"), - ) - } - _ => return_error!(InvalidMonomorphization::SimdShuffle { - span, - name, - ty: args[2].layout.ty - }), + if name == sym::simd_shuffle { + // Make sure this is actually an array, since typeck only checks the length-suffixed + // version of this intrinsic. + let n: u64 = match args[2].layout.ty.kind() { + ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { + len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( + || span_bug!(span, "could not evaluate shuffle index array length"), + ) } - } else { - stripped.parse().unwrap_or_else(|_| { - span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") - }) + _ => return_error!(InvalidMonomorphization::SimdShuffle { + span, + name, + ty: args[2].layout.ty + }), }; - require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); @@ -202,7 +192,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( if name == sym::simd_insert { require!( in_elem == arg_tys[2], - InvalidMonomorphization::InsertedType { span, name, in_elem, in_ty, out_ty: arg_tys[2] } + InvalidMonomorphization::InsertedType { + span, + name, + in_elem, + in_ty, + out_ty: arg_tys[2] + } ); let vector = args[0].immediate(); let index = args[1].immediate(); @@ -228,7 +224,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( if name == sym::simd_select { let m_elem_ty = in_elem; let m_len = in_len; - require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }); + require_simd!( + arg_tys[1], + InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] } + ); let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( m_len == v_len, @@ -241,7 +240,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate())); } - #[cfg(feature="master")] + #[cfg(feature = "master")] if name == sym::simd_cast || name == sym::simd_as { require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); @@ -267,19 +266,17 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( Unsupported, } - let in_style = - match in_elem.kind() { - ty::Int(_) | ty::Uint(_) => Style::Int, - ty::Float(_) => Style::Float, - _ => Style::Unsupported, - }; + let in_style = match in_elem.kind() { + ty::Int(_) | ty::Uint(_) => Style::Int, + ty::Float(_) => Style::Float, + _ => Style::Unsupported, + }; - let out_style = - match out_elem.kind() { - ty::Int(_) | ty::Uint(_) => Style::Int, - ty::Float(_) => Style::Float, - _ => Style::Unsupported, - }; + let out_style = match out_elem.kind() { + ty::Int(_) | ty::Uint(_) => Style::Int, + ty::Float(_) => Style::Float, + _ => Style::Unsupported, + }; match (in_style, out_style) { (Style::Unsupported, Style::Unsupported) => { @@ -294,7 +291,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( out_elem } ); - }, + } _ => return Ok(bx.context.convert_vector(None, args[0].immediate(), llret_ty)), } } @@ -342,10 +339,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let mut shift = 0; for i in 0..in_len { - let elem = bx.extract_element(vector, bx.context.new_rvalue_from_int(bx.int_type, i as i32)); + let elem = + bx.extract_element(vector, bx.context.new_rvalue_from_int(bx.int_type, i as i32)); let shifted = elem >> sign_shift; let masked = shifted & one; - result = result | (bx.context.new_cast(None, masked, result_type) << bx.context.new_rvalue_from_int(result_type, shift)); + result = result + | (bx.context.new_cast(None, masked, result_type) + << bx.context.new_rvalue_from_int(result_type, shift)); shift += 1; } @@ -394,46 +394,50 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Err(()); }}; } - let (elem_ty_str, elem_ty) = - if let ty::Float(f) = in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 32 => ("f", elem_ty), - 64 => ("", elem_ty), - _ => { - return_error!(InvalidMonomorphization::FloatingPointVector { span, name, f_ty: *f, in_ty }); - } + let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() { + let elem_ty = bx.cx.type_float_from_ty(*f); + match f.bit_width() { + 32 => ("f", elem_ty), + 64 => ("", elem_ty), + _ => { + return_error!(InvalidMonomorphization::FloatingPointVector { + span, + name, + f_ty: *f, + in_ty + }); } } - else { - return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); - }; + } else { + return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); - let intr_name = - match name { - sym::simd_ceil => "ceil", - sym::simd_fabs => "fabs", // TODO(antoyo): pand with 170141183420855150465331762880109871103 - sym::simd_fcos => "cos", - sym::simd_fexp2 => "exp2", - sym::simd_fexp => "exp", - sym::simd_flog10 => "log10", - sym::simd_flog2 => "log2", - sym::simd_flog => "log", - sym::simd_floor => "floor", - sym::simd_fma => "fma", - sym::simd_fpowi => "__builtin_powi", - sym::simd_fpow => "pow", - sym::simd_fsin => "sin", - sym::simd_fsqrt => "sqrt", - sym::simd_round => "round", - sym::simd_trunc => "trunc", - _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }) - }; + let intr_name = match name { + sym::simd_ceil => "ceil", + sym::simd_fabs => "fabs", // TODO(antoyo): pand with 170141183420855150465331762880109871103 + sym::simd_fcos => "cos", + sym::simd_fexp2 => "exp2", + sym::simd_fexp => "exp", + sym::simd_flog10 => "log10", + sym::simd_flog2 => "log2", + sym::simd_flog => "log", + sym::simd_floor => "floor", + sym::simd_fma => "fma", + sym::simd_fpowi => "__builtin_powi", + sym::simd_fpow => "pow", + sym::simd_fsin => "sin", + sym::simd_fsqrt => "sqrt", + sym::simd_round => "round", + sym::simd_trunc => "trunc", + _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), + }; let builtin_name = format!("{}{}", intr_name, elem_ty_str); let funcs = bx.cx.functions.borrow(); - let function = funcs.get(&builtin_name).unwrap_or_else(|| panic!("unable to find builtin function {}", builtin_name)); + let function = funcs + .get(&builtin_name) + .unwrap_or_else(|| panic!("unable to find builtin function {}", builtin_name)); // TODO(antoyo): add platform-specific behavior here for architectures that have these // intrinsics as instructions (for instance, gpus) @@ -479,8 +483,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); } - #[cfg(feature="master")] - fn vector_ty<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, elem_ty: Ty<'tcx>, vec_len: u64) -> Type<'gcc> { + #[cfg(feature = "master")] + fn vector_ty<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + elem_ty: Ty<'tcx>, + vec_len: u64, + ) -> Type<'gcc> { // FIXME: use cx.layout_of(ty).llvm_type() ? let elem_ty = match *elem_ty.kind() { ty::Int(v) => cx.type_int_from_ty(v), @@ -491,15 +499,22 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( cx.type_vector(elem_ty, vec_len) } - #[cfg(feature="master")] - fn gather<'a, 'gcc, 'tcx>(default: RValue<'gcc>, pointers: RValue<'gcc>, mask: RValue<'gcc>, pointer_count: usize, bx: &mut Builder<'a, 'gcc, 'tcx>, in_len: u64, underlying_ty: Ty<'tcx>, invert: bool) -> RValue<'gcc> { - let vector_type = - if pointer_count > 1 { - bx.context.new_vector_type(bx.usize_type, in_len) - } - else { - vector_ty(bx, underlying_ty, in_len) - }; + #[cfg(feature = "master")] + fn gather<'a, 'gcc, 'tcx>( + default: RValue<'gcc>, + pointers: RValue<'gcc>, + mask: RValue<'gcc>, + pointer_count: usize, + bx: &mut Builder<'a, 'gcc, 'tcx>, + in_len: u64, + underlying_ty: Ty<'tcx>, + invert: bool, + ) -> RValue<'gcc> { + let vector_type = if pointer_count > 1 { + bx.context.new_vector_type(bx.usize_type, in_len) + } else { + vector_ty(bx, underlying_ty, in_len) + }; let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type(); let mut values = vec![]; @@ -530,13 +545,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( if invert { bx.shuffle_vector(vector, default, mask) - } - else { + } else { bx.shuffle_vector(default, vector, mask) } } - #[cfg(feature="master")] + #[cfg(feature = "master")] if name == sym::simd_gather { // simd_gather(values: , pointers: , // mask: ) -> @@ -546,8 +560,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // All types must be simd vector types require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty }); - require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }); - require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }); + require_simd!( + arg_tys[1], + InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] } + ); + require_simd!( + arg_tys[2], + InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] } + ); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); // Of the same length: @@ -641,10 +661,19 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } } - return Ok(gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, false)); + return Ok(gather( + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + pointer_count, + bx, + in_len, + underlying_ty, + false, + )); } - #[cfg(feature="master")] + #[cfg(feature = "master")] if name == sym::simd_scatter { // simd_scatter(values: , pointers: , // mask: ) -> () @@ -654,8 +683,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // All types must be simd vector types require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty }); - require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }); - require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }); + require_simd!( + arg_tys[1], + InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] } + ); + require_simd!( + arg_tys[2], + InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] } + ); // Of the same length: let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx()); @@ -744,17 +779,24 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } } - let result = gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, true); + let result = gather( + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + pointer_count, + bx, + in_len, + underlying_ty, + true, + ); let pointers = args[1].immediate(); - let vector_type = - if pointer_count > 1 { - bx.context.new_vector_type(bx.usize_type, in_len) - } - else { - vector_ty(bx, underlying_ty, in_len) - }; + let vector_type = if pointer_count > 1 { + bx.context.new_vector_type(bx.usize_type, in_len) + } else { + vector_ty(bx, underlying_ty, in_len) + }; let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type(); for i in 0..in_len { @@ -809,11 +851,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; - let (signed, elem_width, elem_ty) = - match *in_elem.kind() { - ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_int_from_ty(i)), - ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_uint_from_ty(i)), - _ => { + let (signed, elem_width, elem_ty) = match *in_elem.kind() { + ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_int_from_ty(i)), + ty::Uint(i) => { + (false, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_uint_from_ty(i)) + } + _ => { return_error!(InvalidMonomorphization::ExpectedVectorElementType { span, name, @@ -823,77 +866,82 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } }; - let result = - match (signed, is_add) { - (false, true) => { - let res = lhs + rhs; - let cmp = bx.context.new_comparison(None, ComparisonOp::LessThan, res, lhs); - res | cmp - }, - (true, true) => { - // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition - // TODO(antoyo): improve using conditional operators if possible. - // TODO(antoyo): dyncast_vector should not require a call to unqualified. - let arg_type = lhs.get_type().unqualified(); - // TODO(antoyo): convert lhs and rhs to unsigned. - let sum = lhs + rhs; - let vector_type = arg_type.dyncast_vector().expect("vector type"); - let unit = vector_type.get_num_units(); - let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1); - let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]); + let result = match (signed, is_add) { + (false, true) => { + let res = lhs + rhs; + let cmp = bx.context.new_comparison(None, ComparisonOp::LessThan, res, lhs); + res | cmp + } + (true, true) => { + // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition + // TODO(antoyo): improve using conditional operators if possible. + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let arg_type = lhs.get_type().unqualified(); + // TODO(antoyo): convert lhs and rhs to unsigned. + let sum = lhs + rhs; + let vector_type = arg_type.dyncast_vector().expect("vector type"); + let unit = vector_type.get_num_units(); + let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1); + let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]); - let xor1 = lhs ^ rhs; - let xor2 = lhs ^ sum; - let and = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2; - let mask = and >> width; + let xor1 = lhs ^ rhs; + let xor2 = lhs ^ sum; + let and = + bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2; + let mask = and >> width; - let one = bx.context.new_rvalue_one(elem_ty); - let ones = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]); - let shift1 = ones << width; - let shift2 = sum >> width; - let mask_min = shift1 ^ shift2; + let one = bx.context.new_rvalue_one(elem_ty); + let ones = + bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]); + let shift1 = ones << width; + let shift2 = sum >> width; + let mask_min = shift1 ^ shift2; - let and1 = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum; - let and2 = mask & mask_min; + let and1 = + bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum; + let and2 = mask & mask_min; - and1 + and2 - }, - (false, false) => { - let res = lhs - rhs; - let cmp = bx.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs); - res & cmp - }, - (true, false) => { - // TODO(antoyo): dyncast_vector should not require a call to unqualified. - let arg_type = lhs.get_type().unqualified(); - // TODO(antoyo): this uses the same algorithm from saturating add, but add the - // negative of the right operand. Find a proper subtraction algorithm. - let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs); + and1 + and2 + } + (false, false) => { + let res = lhs - rhs; + let cmp = bx.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs); + res & cmp + } + (true, false) => { + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let arg_type = lhs.get_type().unqualified(); + // TODO(antoyo): this uses the same algorithm from saturating add, but add the + // negative of the right operand. Find a proper subtraction algorithm. + let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs); - // TODO(antoyo): convert lhs and rhs to unsigned. - let sum = lhs + rhs; - let vector_type = arg_type.dyncast_vector().expect("vector type"); - let unit = vector_type.get_num_units(); - let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1); - let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]); + // TODO(antoyo): convert lhs and rhs to unsigned. + let sum = lhs + rhs; + let vector_type = arg_type.dyncast_vector().expect("vector type"); + let unit = vector_type.get_num_units(); + let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1); + let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]); - let xor1 = lhs ^ rhs; - let xor2 = lhs ^ sum; - let and = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2; - let mask = and >> width; + let xor1 = lhs ^ rhs; + let xor2 = lhs ^ sum; + let and = + bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2; + let mask = and >> width; - let one = bx.context.new_rvalue_one(elem_ty); - let ones = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]); - let shift1 = ones << width; - let shift2 = sum >> width; - let mask_min = shift1 ^ shift2; + let one = bx.context.new_rvalue_one(elem_ty); + let ones = + bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]); + let shift1 = ones << width; + let shift2 = sum >> width; + let mask_min = shift1 ^ shift2; - let and1 = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum; - let and2 = mask & mask_min; + let and1 = + bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum; + let and2 = mask & mask_min; - and1 + and2 - } - }; + and1 + and2 + } + }; return Ok(result); } @@ -968,7 +1016,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( 1.0 ); - macro_rules! minmax_red { ($name:ident: $int_red:ident, $float_red:ident) => { if name == sym::$name { @@ -979,13 +1026,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => Ok(bx.$int_red(args[0].immediate())), ty::Float(_) => Ok(bx.$float_red(args[0].immediate())), - _ => return_error!(InvalidMonomorphization::UnsupportedSymbol { - span, + _ => return_error!(InvalidMonomorphization::UnsupportedSymbol { + span, name, symbol: sym::$name, in_ty, - in_elem, - ret_ty + in_elem, + ret_ty }), }; } @@ -1025,7 +1072,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.vector_reduce_op(input, $op); - Ok(if !$boolean { r } else { bx.icmp(IntPredicate::IntNE, r, bx.context.new_rvalue_zero(r.get_type())) }) + Ok(if !$boolean { + r + } else { + bx.icmp( + IntPredicate::IntNE, + r, + bx.context.new_rvalue_zero(r.get_type()), + ) + }) } _ => return_error!(InvalidMonomorphization::UnsupportedSymbol { span, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 86c39ab5e94..6f1e4c5178a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1020,28 +1020,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>( )); } - if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") { - // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer. - // If there is no suffix, use the index array length. - let n: u64 = if stripped.is_empty() { - // Make sure this is actually an array, since typeck only checks the length-suffixed - // version of this intrinsic. - match args[2].layout.ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { - len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( - || span_bug!(span, "could not evaluate shuffle index array length"), - ) - } - _ => return_error!(InvalidMonomorphization::SimdShuffle { - span, - name, - ty: args[2].layout.ty - }), + if name == sym::simd_shuffle { + // Make sure this is actually an array, since typeck only checks the length-suffixed + // version of this intrinsic. + let n: u64 = match args[2].layout.ty.kind() { + ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { + len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( + || span_bug!(span, "could not evaluate shuffle index array length"), + ) } - } else { - stripped.parse().unwrap_or_else(|_| { - span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") - }) + _ => return_error!(InvalidMonomorphization::SimdShuffle { + span, + name, + ty: args[2].layout.ty + }), }; require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index f13dfd96b8e..4f26383ed05 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -862,11 +862,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .iter() .enumerate() .map(|(i, arg)| { - // The indices passed to simd_shuffle* in the + // The indices passed to simd_shuffle in the // third argument must be constant. This is // checked by const-qualification, which also // promotes any complex rvalues to constants. - if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") { + if i == 2 && intrinsic == sym::simd_shuffle { if let mir::Operand::Constant(constant) = arg { let (llval, ty) = self.simd_shuffle_indices(&bx, constant); return OperandRef { diff --git a/compiler/rustc_error_codes/src/error_codes/E0439.md b/compiler/rustc_error_codes/src/error_codes/E0439.md index 24268aef222..369226c383e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0439.md +++ b/compiler/rustc_error_codes/src/error_codes/E0439.md @@ -16,7 +16,7 @@ extern "platform-intrinsic" { The `simd_shuffle` function needs the length of the array passed as last parameter in its name. Example: -``` +```ignore (no longer compiles) #![feature(platform_intrinsics)] extern "platform-intrinsic" { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 064021b1ea4..970efaf312c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -567,20 +567,6 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) | sym::simd_reduce_min_nanless | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)), sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)), - name if name.as_str().starts_with("simd_shuffle") => { - match name.as_str()["simd_shuffle".len()..].parse() { - Ok(n) => { - let params = vec![param(0), param(0), Ty::new_array(tcx, tcx.types.u32, n)]; - (2, params, param(1)) - } - Err(_) => { - let msg = - format!("unrecognized platform-specific intrinsic function: `{name}`"); - tcx.sess.struct_span_err(it.span, msg).emit(); - return; - } - } - } _ => { let msg = format!("unrecognized platform-specific intrinsic function: `{name}`"); tcx.sess.struct_span_err(it.span, msg).emit(); diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index d1ecfe9f851..fc36c6e4124 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -305,7 +305,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Unreachable; } } - _ if intrinsic_name.as_str().starts_with("simd_shuffle") => { + sym::simd_shuffle => { validate_simd_shuffle(tcx, args, terminator.source_info.span); } _ => {} diff --git a/tests/incremental/issue-61530.rs b/tests/incremental/issue-61530.rs index edb3d60ba3f..1dcb41ddeda 100644 --- a/tests/incremental/issue-61530.rs +++ b/tests/incremental/issue-61530.rs @@ -6,13 +6,13 @@ struct I32x2(i32, i32); extern "platform-intrinsic" { - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle(x: T, y: T, idx: I) -> U; } fn main() { unsafe { const IDX: [u32; 2] = [0, 0]; - let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), IDX); - let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), IDX); + let _: I32x2 = simd_shuffle(I32x2(1, 2), I32x2(3, 4), IDX); + let _: I32x2 = simd_shuffle(I32x2(1, 2), I32x2(3, 4), IDX); } } diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index 3c913c0adfa..905c3b8d3cc 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -22,9 +22,7 @@ extern "platform-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; fn simd_extract(x: T, idx: u32) -> E; - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; - fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; - fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; + fn simd_shuffle(x: T, y: T, idx: I) -> U; } macro_rules! all_eq { @@ -83,19 +81,19 @@ fn main() { let y4 = i32x4(140, 141, 142, 143); let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); unsafe { - all_eq!(simd_shuffle2(x2, y2, const { [3u32, 0] }), i32x2(121, 20)); - all_eq!(simd_shuffle4(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120)); - all_eq!(simd_shuffle8(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }), + all_eq!(simd_shuffle(x2, y2, const { [3u32, 0] }), i32x2(121, 20)); + all_eq!(simd_shuffle(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120)); + all_eq!(simd_shuffle(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }), i32x8(121, 20, 21, 120, 21, 120, 121, 20)); - all_eq!(simd_shuffle2(x4, y4, const { [7u32, 2] }), i32x2(143, 42)); - all_eq!(simd_shuffle4(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40)); - all_eq!(simd_shuffle8(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }), + all_eq!(simd_shuffle(x4, y4, const { [7u32, 2] }), i32x2(143, 42)); + all_eq!(simd_shuffle(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40)); + all_eq!(simd_shuffle(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }), i32x8(143, 42, 141, 40, 43, 142, 140, 41)); - all_eq!(simd_shuffle2(x8, y8, const { [11u32, 5] }), i32x2(183, 85)); - all_eq!(simd_shuffle4(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80)); - all_eq!(simd_shuffle8(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }), + all_eq!(simd_shuffle(x8, y8, const { [11u32, 5] }), i32x2(183, 85)); + all_eq!(simd_shuffle(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80)); + all_eq!(simd_shuffle(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }), i32x8(183, 85, 187, 80, 83, 180, 184, 81)); } diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs index abde69163bd..0ff2203ec72 100644 --- a/tests/ui/simd/intrinsic/generic-elements.rs +++ b/tests/ui/simd/intrinsic/generic-elements.rs @@ -34,9 +34,7 @@ extern "platform-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; fn simd_extract(x: T, idx: u32) -> E; - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; - fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; - fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; + fn simd_shuffle(x: T, y: T, idx: I) -> U; } fn main() { @@ -51,27 +49,27 @@ fn main() { //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32` const IDX2: [u32; 2] = [0; 2]; - simd_shuffle2::(0, 0, IDX2); + simd_shuffle::(0, 0, IDX2); //~^ ERROR expected SIMD input type, found non-SIMD `i32` const IDX4: [u32; 4] = [0; 4]; - simd_shuffle4::(0, 0, IDX4); + simd_shuffle::(0, 0, IDX4); //~^ ERROR expected SIMD input type, found non-SIMD `i32` const IDX8: [u32; 8] = [0; 8]; - simd_shuffle8::(0, 0, IDX8); + simd_shuffle::(0, 0, IDX8); //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_shuffle2::<_, f32x2>(x, x, IDX2); + simd_shuffle::<_, _, f32x2>(x, x, IDX2); //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - simd_shuffle4::<_, f32x4>(x, x, IDX4); + simd_shuffle::<_, _, f32x4>(x, x, IDX4); //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - simd_shuffle8::<_, f32x8>(x, x, IDX8); + simd_shuffle::<_, _, f32x8>(x, x, IDX8); //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - simd_shuffle2::<_, i32x8>(x, x, IDX2); + simd_shuffle::<_, _, i32x8>(x, x, IDX2); //~^ ERROR expected return type of length 2, found `i32x8` with length 8 - simd_shuffle4::<_, i32x8>(x, x, IDX4); + simd_shuffle::<_, _, i32x8>(x, x, IDX4); //~^ ERROR expected return type of length 4, found `i32x8` with length 8 - simd_shuffle8::<_, i32x2>(x, x, IDX8); + simd_shuffle::<_, _, i32x2>(x, x, IDX8); //~^ ERROR expected return type of length 8, found `i32x2` with length 2 } } diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr index 5b423f7040f..115d9d4b3f3 100644 --- a/tests/ui/simd/intrinsic/generic-elements.stderr +++ b/tests/ui/simd/intrinsic/generic-elements.stderr @@ -1,74 +1,74 @@ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:46:9 + --> $DIR/generic-elements.rs:44:9 | LL | simd_insert(0, 0, 0); | ^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` - --> $DIR/generic-elements.rs:48:9 + --> $DIR/generic-elements.rs:46:9 | LL | simd_insert(x, 0, 1.0); | ^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` - --> $DIR/generic-elements.rs:50:9 + --> $DIR/generic-elements.rs:48:9 | LL | simd_extract::<_, f32>(x, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:54:9 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:52:9 | -LL | simd_shuffle2::(0, 0, IDX2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::(0, 0, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:57:9 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:55:9 | -LL | simd_shuffle4::(0, 0, IDX4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::(0, 0, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:60:9 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:58:9 | -LL | simd_shuffle8::(0, 0, IDX8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::(0, 0, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + --> $DIR/generic-elements.rs:61:9 + | +LL | simd_shuffle::<_, _, f32x2>(x, x, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` --> $DIR/generic-elements.rs:63:9 | -LL | simd_shuffle2::<_, f32x2>(x, x, IDX2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::<_, _, f32x4>(x, x, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` --> $DIR/generic-elements.rs:65:9 | -LL | simd_shuffle4::<_, f32x4>(x, x, IDX4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::<_, _, f32x8>(x, x, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:67:9 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `i32x8` with length 8 + --> $DIR/generic-elements.rs:68:9 | -LL | simd_shuffle8::<_, f32x8>(x, x, IDX8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::<_, _, i32x8>(x, x, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 4, found `i32x8` with length 8 --> $DIR/generic-elements.rs:70:9 | -LL | simd_shuffle2::<_, i32x8>(x, x, IDX2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::<_, _, i32x8>(x, x, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 8, found `i32x2` with length 2 --> $DIR/generic-elements.rs:72:9 | -LL | simd_shuffle4::<_, i32x8>(x, x, IDX4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:74:9 - | -LL | simd_shuffle8::<_, i32x2>(x, x, IDX8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_shuffle::<_, _, i32x2>(x, x, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs index 7221b3ab769..5ca684a9d78 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs @@ -6,7 +6,7 @@ #![feature(platform_intrinsics, repr_simd)] extern "platform-intrinsic" { - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle(x: T, y: T, idx: I) -> U; } #[repr(simd)] @@ -22,5 +22,5 @@ fn main() { #[inline(always)] unsafe fn inline_me() -> Simd2 { const IDX: [u32; 2] = [0, 3]; - simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) + simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX) } diff --git a/tests/ui/simd/intrinsic/inlining-issue67557.rs b/tests/ui/simd/intrinsic/inlining-issue67557.rs index 0d15427095a..5633ad70cd3 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557.rs @@ -6,7 +6,7 @@ #![feature(platform_intrinsics, repr_simd)] extern "platform-intrinsic" { - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle(x: T, y: T, idx: I) -> U; } #[repr(simd)] @@ -16,7 +16,7 @@ struct Simd2(u8, u8); fn main() { unsafe { const IDX: [u32; 2] = [0, 1]; - let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX); + let p_res: Simd2 = simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX); let a_res: Simd2 = inline_me(); assert_10_11(p_res); @@ -38,5 +38,5 @@ fn assert_10_13(x: Simd2) { #[inline(always)] unsafe fn inline_me() -> Simd2 { const IDX: [u32; 2] = [0, 3]; - simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) + simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX) } diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.rs b/tests/ui/simd/shuffle-not-out-of-bounds.rs index 0dee3a0e869..18939bcc5b4 100644 --- a/tests/ui/simd/shuffle-not-out-of-bounds.rs +++ b/tests/ui/simd/shuffle-not-out-of-bounds.rs @@ -29,12 +29,7 @@ struct u8x32([u8; 32]); struct u8x64([u8; 64]); extern "platform-intrinsic" { - pub fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; - pub fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; - pub fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; - pub fn simd_shuffle16(x: T, y: T, idx: [u32; 16]) -> U; - pub fn simd_shuffle32(x: T, y: T, idx: [u32; 32]) -> U; - pub fn simd_shuffle64(x: T, y: T, idx: [u32; 64]) -> U; + pub fn simd_shuffle(x: T, y: T, idx: I) -> U; } // Test vectors by lane size. Since LLVM does not distinguish between a shuffle @@ -58,22 +53,22 @@ macro_rules! test_shuffle_lanes { } } } -//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle2` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle4` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle8` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle16` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle32` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle64` intrinsic +//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic // Because the test is mostly embedded in a macro, all the errors have the same origin point. // And unfortunately, standard comments, as in the UI test harness, disappear in macros! fn main() { - test_shuffle_lanes!(2, u8x2, simd_shuffle2); - test_shuffle_lanes!(4, u8x4, simd_shuffle4); - test_shuffle_lanes!(8, u8x8, simd_shuffle8); - test_shuffle_lanes!(16, u8x16, simd_shuffle16); - test_shuffle_lanes!(32, u8x32, simd_shuffle32); - test_shuffle_lanes!(64, u8x64, simd_shuffle64); + test_shuffle_lanes!(2, u8x2, simd_shuffle); + test_shuffle_lanes!(4, u8x4, simd_shuffle); + test_shuffle_lanes!(8, u8x8, simd_shuffle); + test_shuffle_lanes!(16, u8x16, simd_shuffle); + test_shuffle_lanes!(32, u8x32, simd_shuffle); + test_shuffle_lanes!(64, u8x64, simd_shuffle); extern "platform-intrinsic" { fn simd_shuffle(a: T, b: T, i: I) -> U; diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.stderr b/tests/ui/simd/shuffle-not-out-of-bounds.stderr index 415f04d933f..59e5ab85866 100644 --- a/tests/ui/simd/shuffle-not-out-of-bounds.stderr +++ b/tests/ui/simd/shuffle-not-out-of-bounds.stderr @@ -1,71 +1,71 @@ -error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: shuffle index #0 is out of bounds (limit 4) - --> $DIR/shuffle-not-out-of-bounds.rs:56:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4) + --> $DIR/shuffle-not-out-of-bounds.rs:51:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(2, u8x2, simd_shuffle2); - | ------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(2, u8x2, simd_shuffle); + | ------------------------------------------ in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: shuffle index #0 is out of bounds (limit 8) - --> $DIR/shuffle-not-out-of-bounds.rs:56:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 8) + --> $DIR/shuffle-not-out-of-bounds.rs:51:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(4, u8x4, simd_shuffle4); - | ------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(4, u8x4, simd_shuffle); + | ------------------------------------------ in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: shuffle index #0 is out of bounds (limit 16) - --> $DIR/shuffle-not-out-of-bounds.rs:56:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 16) + --> $DIR/shuffle-not-out-of-bounds.rs:51:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(8, u8x8, simd_shuffle8); - | ------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(8, u8x8, simd_shuffle); + | ------------------------------------------ in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle16` intrinsic: shuffle index #0 is out of bounds (limit 32) - --> $DIR/shuffle-not-out-of-bounds.rs:56:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 32) + --> $DIR/shuffle-not-out-of-bounds.rs:51:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(16, u8x16, simd_shuffle16); - | ---------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(16, u8x16, simd_shuffle); + | -------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle32` intrinsic: shuffle index #0 is out of bounds (limit 64) - --> $DIR/shuffle-not-out-of-bounds.rs:56:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 64) + --> $DIR/shuffle-not-out-of-bounds.rs:51:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(32, u8x32, simd_shuffle32); - | ---------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(32, u8x32, simd_shuffle); + | -------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle64` intrinsic: shuffle index #0 is out of bounds (limit 128) - --> $DIR/shuffle-not-out-of-bounds.rs:56:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 128) + --> $DIR/shuffle-not-out-of-bounds.rs:51:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(64, u8x64, simd_shuffle64); - | ---------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(64, u8x64, simd_shuffle); + | -------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4) - --> $DIR/shuffle-not-out-of-bounds.rs:84:23 + --> $DIR/shuffle-not-out-of-bounds.rs:79:23 | LL | let _: u8x2 = simd_shuffle(v, v, I); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs index 461243d4892..838e31f8e41 100644 --- a/tests/ui/simd/shuffle.rs +++ b/tests/ui/simd/shuffle.rs @@ -8,7 +8,6 @@ extern "platform-intrinsic" { fn simd_shuffle(a: T, b: T, i: I) -> U; - fn simd_shuffle16(x: T, y: T, idx: [u32; 16]) -> U; } #[derive(Copy, Clone)] @@ -16,7 +15,7 @@ extern "platform-intrinsic" { struct Simd([T; N]); pub unsafe fn __shuffle_vector16(x: T, y: T) -> U { - simd_shuffle16(x, y, IDX) + simd_shuffle(x, y, IDX) } fn main() { From 5992e9b2fe64600158448f65890324f9ecfe63d5 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 3 Aug 2023 14:07:37 +0200 Subject: [PATCH 50/62] builtin impl confirmation wuhu --- .../src/traits/select/confirmation.rs | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index bf09681c66d..cf9d2bda17e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -987,9 +987,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let target = self.infcx.shallow_resolve(target); debug!(?source, ?target, "confirm_builtin_unsize_candidate"); - let mut nested = vec![]; - let src; - match (source.kind(), target.kind()) { + Ok(match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b)) if dyn_a == dyn_b => @@ -1016,16 +1014,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. - let InferOk { obligations, .. } = self + let InferOk { mut obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) .sup(DefineOpaqueTypes::No, target, source_trait) .map_err(|_| Unimplemented)?; - nested.extend(obligations); // Register one obligation for 'a: 'b. let outlives = ty::OutlivesPredicate(r_a, r_b); - nested.push(Obligation::with_depth( + obligations.push(Obligation::with_depth( tcx, obligation.cause.clone(), obligation.recursion_depth + 1, @@ -1033,7 +1030,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.rebind(outlives), )); - src = BuiltinImplSource::Misc; + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } // `T` -> `Trait` @@ -1059,11 +1056,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // words, if the object type is `Foo + Send`, this would create an obligation for // the `Send` check.) // - Projection predicates - nested.extend( - data.iter().map(|predicate| { - predicate_to_obligation(predicate.with_self_ty(tcx, source)) - }), - ); + let mut nested: Vec<_> = data + .iter() + .map(|predicate| predicate_to_obligation(predicate.with_self_ty(tcx, source))) + .collect(); // We can only make objects from sized types. let tr = ty::TraitRef::from_lang_item( @@ -1081,7 +1077,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx), )); - src = BuiltinImplSource::Misc; + ImplSource::Builtin(BuiltinImplSource::Misc, nested) } // `[T; n]` -> `[T]` @@ -1091,9 +1087,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, b, a) .map_err(|_| Unimplemented)?; - nested.extend(obligations); - src = BuiltinImplSource::Misc; + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } // `Struct` -> `Struct` @@ -1106,6 +1101,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tail_field = def.non_enum_variant().tail(); let tail_field_ty = tcx.type_of(tail_field.did); + let mut nested = vec![]; + // Extract `TailField` and `TailField` from `Struct` and `Struct`, // normalizing in the process, since `type_of` returns something directly from // astconv (which means it's un-normalized). @@ -1151,7 +1148,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); nested.push(tail_unsize_obligation); - src = BuiltinImplSource::Misc; + ImplSource::Builtin(BuiltinImplSource::Misc, nested) } // `(.., T)` -> `(.., U)` @@ -1166,27 +1163,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // last element is equal to the target. let new_tuple = Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last))); - let InferOk { obligations, .. } = self + let InferOk { mut obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, target, new_tuple) .map_err(|_| Unimplemented)?; - nested.extend(obligations); // Add a nested `T: Unsize` predicate. let last_unsize_obligation = obligation.with( tcx, ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]), ); - nested.push(last_unsize_obligation); + obligations.push(last_unsize_obligation); - src = BuiltinImplSource::TupleUnsizing; + ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, obligations) } _ => bug!("source: {source}, target: {target}"), - }; - - Ok(ImplSource::Builtin(src, nested)) + }) } fn confirm_const_destruct_candidate( From 5830ca216d0bd8b0e2f16b0022db25114d80acb6 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 9 Mar 2023 20:54:53 +0000 Subject: [PATCH 51/62] Add `internal_features` lint It lints against features that are inteded to be internal to the compiler and standard library. Implements MCP #596. We allow `internal_features` in the standard library and compiler as those use many features and this _is_ the standard library from the "internal to the compiler and standard library" after all. Marking some features as internal wasn't exactly the most scientific approach, I just marked some mostly obvious features. While there is a categorization in the macro, it's not very well upheld (should probably be fixed in another PR). We always pass `-Ainternal_features` in the testsuite About 400 UI tests and several other tests use internal features. Instead of throwing the attribute on each one, just always allow them. There's nothing wrong with testing internal features^^ --- compiler/rustc_abi/src/lib.rs | 1 + compiler/rustc_arena/src/lib.rs | 1 + compiler/rustc_borrowck/src/lib.rs | 1 + compiler/rustc_data_structures/src/lib.rs | 1 + .../src/error_codes/E0092.md | 2 + .../src/error_codes/E0093.md | 2 + .../src/error_codes/E0094.md | 2 + .../src/error_codes/E0208.md | 1 + .../src/error_codes/E0211.md | 2 + .../src/error_codes/E0230.md | 1 + .../src/error_codes/E0231.md | 1 + .../src/error_codes/E0232.md | 1 + .../src/error_codes/E0264.md | 2 + .../src/error_codes/E0539.md | 2 + .../src/error_codes/E0542.md | 2 + .../src/error_codes/E0543.md | 2 + .../src/error_codes/E0544.md | 2 + .../src/error_codes/E0545.md | 2 + .../src/error_codes/E0546.md | 2 + .../src/error_codes/E0547.md | 2 + .../src/error_codes/E0549.md | 2 + .../src/error_codes/E0622.md | 4 + .../src/error_codes/E0773.md | 2 + .../src/error_codes/E0789.md | 1 + compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_errors/src/lib.rs | 1 + compiler/rustc_expand/src/lib.rs | 1 + compiler/rustc_feature/src/active.rs | 76 +++++++++++++------ compiler/rustc_hir/src/lib.rs | 1 + .../src/assert_module_sources.rs | 1 + compiler/rustc_index/src/lib.rs | 1 + compiler/rustc_lint/messages.ftl | 3 + compiler/rustc_lint/src/builtin.rs | 59 ++++++++++---- compiler/rustc_lint/src/lib.rs | 3 +- compiler/rustc_lint/src/lints.rs | 13 +++- compiler/rustc_lint_defs/src/builtin.rs | 1 - compiler/rustc_macros/src/lib.rs | 1 + compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_parse/src/lib.rs | 1 + compiler/rustc_query_impl/src/lib.rs | 1 + compiler/rustc_resolve/src/lib.rs | 1 + compiler/rustc_session/src/lib.rs | 1 + compiler/rustc_span/src/lib.rs | 1 + compiler/rustc_target/src/lib.rs | 1 + compiler/rustc_type_ir/src/lib.rs | 1 + library/alloc/src/lib.rs | 1 + library/core/src/intrinsics/mir.rs | 3 + library/core/src/lib.rs | 1 + library/panic_abort/src/lib.rs | 1 + library/panic_unwind/src/lib.rs | 1 + library/proc_macro/src/lib.rs | 1 + library/profiler_builtins/src/lib.rs | 1 + library/std/src/lib.rs | 1 + library/test/src/lib.rs | 1 + library/unwind/src/lib.rs | 1 + src/doc/rustdoc/src/unstable-features.md | 1 + .../src/language-features/intrinsics.md | 1 + .../src/language-features/lang-items.md | 3 + src/tools/clippy/tests/compile-test.rs | 1 + src/tools/compiletest/src/runtest.rs | 11 ++- src/tools/miri/tests/compiletest.rs | 1 + src/tools/tidy/src/features.rs | 1 + tests/run-make/tools.mk | 2 +- tests/rustdoc-gui/src/staged_api/lib.rs | 1 + tests/rustdoc-gui/src/test_docs/lib.rs | 1 + tests/rustdoc/issue-18199.rs | 1 + .../feature-gate-unsafe_pin_internals.rs | 4 +- .../feature-gate-unsafe_pin_internals.stderr | 7 +- 68 files changed, 209 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 1442747fe1e..12dd1542d79 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))] +#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))] use std::fmt; #[cfg(feature = "nightly")] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index ba47ebd68cb..f4900ece1cc 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -23,6 +23,7 @@ #![deny(unsafe_op_in_unsafe_fn)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine. use smallvec::SmallVec; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 317af8ae1f6..efe525c224d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -11,6 +11,7 @@ #![feature(trusted_step)] #![feature(try_blocks)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 3deb9c5c2f5..33772089744 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -37,6 +37,7 @@ #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![deny(unsafe_op_in_unsafe_fn)] #[macro_use] diff --git a/compiler/rustc_error_codes/src/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md index 5cbe2a188b0..84ec0656d1a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0092.md +++ b/compiler/rustc_error_codes/src/error_codes/E0092.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0092 #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { fn atomic_foo(); // error: unrecognized atomic operation @@ -17,6 +18,7 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in ``` #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { fn atomic_fence_seqcst(); // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md index b1683cf4fc4..2bda4d74f72 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0093 #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { fn foo(); // error: unrecognized intrinsic function: `foo` @@ -22,6 +23,7 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in ``` #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { fn atomic_fence_seqcst(); // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md index cc546bdbb3b..67a8c3678c5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0094.md +++ b/compiler/rustc_error_codes/src/error_codes/E0094.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0094 #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { #[rustc_safe_intrinsic] @@ -18,6 +19,7 @@ Example: ``` #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { #[rustc_safe_intrinsic] diff --git a/compiler/rustc_error_codes/src/error_codes/E0208.md b/compiler/rustc_error_codes/src/error_codes/E0208.md index c6db9b5d61b..2b811b4b850 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0208.md +++ b/compiler/rustc_error_codes/src/error_codes/E0208.md @@ -8,6 +8,7 @@ Erroneous code example: ```compile_fail // NOTE: this feature is perma-unstable and should *only* be used for // testing purposes. +#![allow(internal_features)] #![feature(rustc_attrs)] #[rustc_variance] diff --git a/compiler/rustc_error_codes/src/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md index 8c2462ebd9b..70f14fffae6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0211.md +++ b/compiler/rustc_error_codes/src/error_codes/E0211.md @@ -5,6 +5,7 @@ used. Erroneous code examples: ```compile_fail #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { #[rustc_safe_intrinsic] @@ -41,6 +42,7 @@ For the first code example, please check the function definition. Example: ``` #![feature(intrinsics)] +#![allow(internal_features)] extern "rust-intrinsic" { #[rustc_safe_intrinsic] diff --git a/compiler/rustc_error_codes/src/error_codes/E0230.md b/compiler/rustc_error_codes/src/error_codes/E0230.md index cfb72e74319..87ea90e73c9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0230.md +++ b/compiler/rustc_error_codes/src/error_codes/E0230.md @@ -5,6 +5,7 @@ compiled: ```compile_fail,E0230 #![feature(rustc_attrs)] +#![allow(internal_features)] #[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{B}>`"] // error trait BadAnnotation {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0231.md b/compiler/rustc_error_codes/src/error_codes/E0231.md index 23a0a88ecdd..a1aaf90df49 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0231.md +++ b/compiler/rustc_error_codes/src/error_codes/E0231.md @@ -5,6 +5,7 @@ compiled: ```compile_fail,E0231 #![feature(rustc_attrs)] +#![allow(internal_features)] #[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{}>`"] // error! trait BadAnnotation {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0232.md b/compiler/rustc_error_codes/src/error_codes/E0232.md index b310caefa6e..0e50cf589ee 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0232.md +++ b/compiler/rustc_error_codes/src/error_codes/E0232.md @@ -5,6 +5,7 @@ compiled: ```compile_fail,E0232 #![feature(rustc_attrs)] +#![allow(internal_features)] #[rustc_on_unimplemented(lorem="")] // error! trait BadAnnotation {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0264.md b/compiler/rustc_error_codes/src/error_codes/E0264.md index e2a27f7b106..d7906076229 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0264.md +++ b/compiler/rustc_error_codes/src/error_codes/E0264.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0264 #![feature(lang_items)] +#![allow(internal_features)] extern "C" { #[lang = "cake"] // error: unknown external lang item: `cake` @@ -16,6 +17,7 @@ A list of available external lang items is available in ``` #![feature(lang_items)] +#![allow(internal_features)] extern "C" { #[lang = "panic_impl"] // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md index c53d60a5f47..cd28afbc48d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0539.md +++ b/compiler/rustc_error_codes/src/error_codes/E0539.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0539 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[deprecated(note)] // error! @@ -28,6 +29,7 @@ To fix these issues you need to give required key-value pairs. ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[deprecated(since = "1.39.0", note = "reason")] // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md index c69e574179b..be186dbd2cc 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0542.md +++ b/compiler/rustc_error_codes/src/error_codes/E0542.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0542 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[stable(feature = "_stable_fn")] // invalid @@ -23,6 +24,7 @@ To fix this issue, you need to provide the `since` field. Example: ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[stable(feature = "_stable_fn", since = "1.0.0")] // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0543.md b/compiler/rustc_error_codes/src/error_codes/E0543.md index d0b2e2f7a7d..5051c72a151 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0543.md +++ b/compiler/rustc_error_codes/src/error_codes/E0543.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0543 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[stable(since = "0.1.0", feature = "_deprecated_fn")] @@ -17,6 +18,7 @@ To fix this issue, you need to provide the `note` field. Example: ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[stable(since = "0.1.0", feature = "_deprecated_fn")] diff --git a/compiler/rustc_error_codes/src/error_codes/E0544.md b/compiler/rustc_error_codes/src/error_codes/E0544.md index 2227e2a06bf..202401f9d45 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0544.md +++ b/compiler/rustc_error_codes/src/error_codes/E0544.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0544 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "rust1")] #[stable(feature = "rust1", since = "1.0.0")] @@ -15,6 +16,7 @@ To fix this issue, ensure that each item has at most one stability attribute. ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "rust1")] #[stable(feature = "test", since = "2.0.0")] // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0545.md b/compiler/rustc_error_codes/src/error_codes/E0545.md index 7aba084f4d3..880378ebd3a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0545.md +++ b/compiler/rustc_error_codes/src/error_codes/E0545.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0545 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[unstable(feature = "_unstable_fn", issue = "0")] // invalid @@ -18,6 +19,7 @@ Example: ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[unstable(feature = "_unstable_fn", issue = "none")] // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0546.md b/compiler/rustc_error_codes/src/error_codes/E0546.md index a33dcb7a9ac..8c98eaa07bb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0546.md +++ b/compiler/rustc_error_codes/src/error_codes/E0546.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0546 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[unstable(issue = "none")] // invalid @@ -17,6 +18,7 @@ To fix this issue, you need to provide the `feature` field. Example: ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[unstable(feature = "unstable_fn", issue = "none")] // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0547.md b/compiler/rustc_error_codes/src/error_codes/E0547.md index 4950325df64..5b0f7cd44cf 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0547.md +++ b/compiler/rustc_error_codes/src/error_codes/E0547.md @@ -4,6 +4,7 @@ Erroneous code example: ```compile_fail,E0547 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[unstable(feature = "_unstable_fn")] // invalid @@ -17,6 +18,7 @@ To fix this issue, you need to provide the `issue` field. Example: ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[unstable(feature = "_unstable_fn", issue = "none")] // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md index 70e458a9867..cc6a47fe253 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0549.md +++ b/compiler/rustc_error_codes/src/error_codes/E0549.md @@ -5,6 +5,7 @@ Erroneous code example: ```compile_fail,E0549 #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[deprecated( @@ -19,6 +20,7 @@ Example: ``` #![feature(staged_api)] +#![allow(internal_features)] #![stable(since = "1.0.0", feature = "test")] #[stable(since = "1.0.0", feature = "test")] diff --git a/compiler/rustc_error_codes/src/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md index 3ba3ed10e5c..5d71ee9949d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0622.md +++ b/compiler/rustc_error_codes/src/error_codes/E0622.md @@ -4,6 +4,8 @@ Erroneous code example: ```compile_fail,E0622 #![feature(intrinsics)] +#![allow(internal_features)] + extern "rust-intrinsic" { pub static breakpoint: fn(); // error: intrinsic must be a function } @@ -17,6 +19,8 @@ error, just declare a function. Example: ```no_run #![feature(intrinsics)] +#![allow(internal_features)] + extern "rust-intrinsic" { pub fn breakpoint(); // ok! } diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md index b19a58bf33d..aa65a475a4f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0773.md +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -5,6 +5,7 @@ Erroneous code example: ```compile_fail,E0773 #![feature(decl_macro)] #![feature(rustc_attrs)] +#![allow(internal_features)] #[rustc_builtin_macro] pub macro test($item:item) { @@ -24,6 +25,7 @@ To fix the issue, remove the duplicate declaration: ``` #![feature(decl_macro)] #![feature(rustc_attrs)] +#![allow(internal_features)] #[rustc_builtin_macro] pub macro test($item:item) { diff --git a/compiler/rustc_error_codes/src/error_codes/E0789.md b/compiler/rustc_error_codes/src/error_codes/E0789.md index 89b7cd422fe..2c0018cc799 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0789.md +++ b/compiler/rustc_error_codes/src/error_codes/E0789.md @@ -10,6 +10,7 @@ Erroneous code example: // used outside of the compiler and standard library. #![feature(rustc_attrs)] #![feature(staged_api)] +#![allow(internal_features)] #![unstable(feature = "foo_module", reason = "...", issue = "123")] diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 77e2c900c0d..3bf15505090 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -4,6 +4,7 @@ #![feature(type_alias_impl_trait)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3d1639db4af..3b753629128 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(error_reporter)] #![allow(incomplete_features)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 83a5043b0aa..c4a9b2ace9a 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -11,6 +11,7 @@ #![feature(try_blocks)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index bbc3d291e20..ff25f744ded 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -16,12 +16,22 @@ macro_rules! set { }}; } +#[derive(PartialEq)] +enum FeatureStatus { + Default, + Incomplete, + Internal, +} + macro_rules! declare_features { - (__status_to_bool active) => { - false + (__status_to_enum active) => { + FeatureStatus::Default }; - (__status_to_bool incomplete) => { - true + (__status_to_enum incomplete) => { + FeatureStatus::Incomplete + }; + (__status_to_enum internal) => { + FeatureStatus::Internal }; ($( $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr, $edition:expr), @@ -83,7 +93,7 @@ macro_rules! declare_features { pub fn incomplete(&self, feature: Symbol) -> bool { match feature { $( - sym::$feature => declare_features!(__status_to_bool $status), + sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Incomplete, )* // accepted and removed features aren't in this file but are never incomplete _ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false, @@ -91,6 +101,22 @@ macro_rules! declare_features { _ => panic!("`{}` was not listed in `declare_features`", feature), } } + + /// Some features are internal to the compiler and standard library and should not + /// be used in normal projects. We warn the user about these + /// to alert them. + pub fn internal(&self, feature: Symbol) -> bool { + match feature { + $( + sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Internal, + )* + // accepted and removed features aren't in this file but are never internal + // (a removed feature might have been internal, but it doesn't matter anymore) + _ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false, + _ if self.declared_lib_features.iter().any(|f| f.0 == feature) => false, + _ => panic!("`{}` was not listed in `declare_features`", feature), + } + } } }; } @@ -137,29 +163,29 @@ declare_features! ( /// Allows using the `vectorcall` ABI. (active, abi_vectorcall, "1.7.0", None, None), /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. - (active, allocator_internals, "1.20.0", None, None), + (internal, allocator_internals, "1.20.0", None, None), /// Allows using `#[allow_internal_unsafe]`. This is an /// attribute on `macro_rules!` and can't use the attribute handling /// below (it has to be checked before expansion possibly makes /// macros disappear). - (active, allow_internal_unsafe, "1.0.0", None, None), + (internal, allow_internal_unsafe, "1.0.0", None, None), /// Allows using `#[allow_internal_unstable]`. This is an /// attribute on `macro_rules!` and can't use the attribute handling /// below (it has to be checked before expansion possibly makes /// macros disappear). - (active, allow_internal_unstable, "1.0.0", None, None), + (internal, allow_internal_unstable, "1.0.0", None, None), /// Allows using anonymous lifetimes in argument-position impl-trait. (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None), /// Allows identifying the `compiler_builtins` crate. - (active, compiler_builtins, "1.13.0", None, None), + (internal, compiler_builtins, "1.13.0", None, None), /// Allows writing custom MIR - (active, custom_mir, "1.65.0", None, None), + (internal, custom_mir, "1.65.0", None, None), /// Outputs useful `assert!` messages (active, generic_assert, "1.63.0", None, None), /// Allows using the `rust-intrinsic`'s "ABI". - (active, intrinsics, "1.0.0", None, None), + (internal, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. - (active, lang_items, "1.0.0", None, None), + (internal, lang_items, "1.0.0", None, None), /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 (active, link_cfg, "1.14.0", None, None), /// Allows the `multiple_supertrait_upcastable` lint. @@ -167,22 +193,22 @@ declare_features! ( /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! (incomplete, negative_bounds, "1.71.0", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. - (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), + (internal, omit_gdb_pretty_printer_section, "1.5.0", None, None), /// Allows using `#[prelude_import]` on glob `use` items. - (active, prelude_import, "1.2.0", None, None), + (internal, prelude_import, "1.2.0", None, None), /// Used to identify crates that contain the profiler runtime. - (active, profiler_runtime, "1.18.0", None, None), + (internal, profiler_runtime, "1.18.0", None, None), /// Allows using `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", None, None), + (internal, rustc_attrs, "1.0.0", None, None), /// Allows using the `#[stable]` and `#[unstable]` attributes. - (active, staged_api, "1.0.0", None, None), + (internal, staged_api, "1.0.0", None, None), /// Added for testing E0705; perma-unstable. - (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), + (internal, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), /// Added for testing unstable lints; perma-unstable. - (active, test_unstable_lint, "1.60.0", None, None), + (internal, test_unstable_lint, "1.60.0", None, None), /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions. - /// Marked `incomplete` since perma-unstable and unsound. - (incomplete, unsafe_pin_internals, "1.60.0", None, None), + /// Marked `internal` since perma-unstable and unsound. + (internal, unsafe_pin_internals, "1.60.0", None, None), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (active, with_negative_coherence, "1.60.0", None, None), @@ -216,19 +242,19 @@ declare_features! ( /// Allows using the `#[linkage = ".."]` attribute. (active, linkage, "1.0.0", Some(29603), None), /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. - (active, needs_panic_runtime, "1.10.0", Some(32837), None), + (internal, needs_panic_runtime, "1.10.0", Some(32837), None), /// Allows using `+bundled,+whole-archive` native libs. (active, packed_bundled_libs, "1.69.0", Some(108081), None), /// Allows using the `#![panic_runtime]` attribute. - (active, panic_runtime, "1.10.0", Some(32837), None), + (internal, panic_runtime, "1.10.0", Some(32837), None), /// Allows using `#[rustc_allow_const_fn_unstable]`. /// This is an attribute on `const fn` for the same /// purpose as `#[allow_internal_unstable]`. - (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), + (internal, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), /// Allows using compiler's own crates. (active, rustc_private, "1.0.0", Some(27812), None), /// Allows using internal rustdoc features like `doc(keyword)`. - (active, rustdoc_internals, "1.58.0", Some(90418), None), + (internal, rustdoc_internals, "1.58.0", Some(90418), None), /// Allows using the `rustdoc::missing_doc_code_examples` lint (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None), /// Allows using `#[start]` on a function indicating that it is the program entrypoint. diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 616de57dc63..34214931a08 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -13,6 +13,7 @@ #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 0111a6d302d..8e22ab4083e 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -6,6 +6,7 @@ //! //! ``` //! # #![feature(rustc_attrs)] +//! # #![allow(internal_features)] //! #![rustc_partition_reused(module="spike", cfg="rpass2")] //! #![rustc_partition_codegened(module="spike-x", cfg="rpass2")] //! ``` diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 6fd9f34b29e..9942c70c4ae 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -12,6 +12,7 @@ test ) )] +#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))] #[cfg(feature = "nightly")] pub mod bit_set; diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index f482e3d7c12..e696a18207b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -72,6 +72,9 @@ lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may n .note = see issue #{$n} for more information .help = consider using `min_{$name}` instead, which is more stable and complete +lint_builtin_internal_features = the feature `{$name}` is internal to the compiler or standard library + .note = using it is strongly discouraged + lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition .suggestion = you can use a raw identifier to stay compatible diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e6917f4b2d3..cc6d5330c33 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -28,8 +28,8 @@ use crate::{ BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, - BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures, - BuiltinIncompleteFeaturesHelp, BuiltinIncompleteFeaturesNote, BuiltinKeywordIdents, + BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, + BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, @@ -2301,12 +2301,36 @@ declare_lint! { "incomplete features that may function improperly in some or all cases" } +declare_lint! { + /// The `internal_features` lint detects unstable features enabled with + /// the [`feature` attribute] that are internal to the compiler or standard + /// library. + /// + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(rustc_attrs)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// These features are an implementation detail of the compiler and standard + /// library and are not supposed to be used in user code. + pub INTERNAL_FEATURES, + Deny, + "internal features are not supposed to be used" +} + declare_lint_pass!( /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`. - IncompleteFeatures => [INCOMPLETE_FEATURES] + IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES] ); -impl EarlyLintPass for IncompleteFeatures { +impl EarlyLintPass for IncompleteInternalFeatures { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { let features = cx.sess().features_untracked(); features @@ -2314,17 +2338,26 @@ impl EarlyLintPass for IncompleteFeatures { .iter() .map(|(name, span, _)| (name, span)) .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) - .filter(|(&name, _)| features.incomplete(name)) + .filter(|(&name, _)| features.incomplete(name) || features.internal(name)) .for_each(|(&name, &span)| { let note = rustc_feature::find_feature_issue(name, GateIssue::Language) - .map(|n| BuiltinIncompleteFeaturesNote { n }); - let help = - HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp); - cx.emit_spanned_lint( - INCOMPLETE_FEATURES, - span, - BuiltinIncompleteFeatures { name, note, help }, - ); + .map(|n| BuiltinFeatureIssueNote { n }); + + if features.incomplete(name) { + let help = + HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp); + cx.emit_spanned_lint( + INCOMPLETE_FEATURES, + span, + BuiltinIncompleteFeatures { name, note, help }, + ); + } else { + cx.emit_spanned_lint( + INTERNAL_FEATURES, + span, + BuiltinInternalFeatures { name, note }, + ); + } }); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 96fd3ccf774..2c8b15de040 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -40,6 +40,7 @@ #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_middle; @@ -173,7 +174,7 @@ early_lint_methods!( WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, - IncompleteFeatures: IncompleteFeatures, + IncompleteInternalFeatures: IncompleteInternalFeatures, RedundantSemicolons: RedundantSemicolons, UnusedDocComment: UnusedDocComment, UnexpectedCfgs: UnexpectedCfgs, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index a6a48bf4ffa..a23eb8b6d47 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -405,18 +405,27 @@ pub struct BuiltinExplicitOutlivesSuggestion { pub struct BuiltinIncompleteFeatures { pub name: Symbol, #[subdiagnostic] - pub note: Option, + pub note: Option, #[subdiagnostic] pub help: Option, } +#[derive(LintDiagnostic)] +#[diag(lint_builtin_internal_features)] +#[note] +pub struct BuiltinInternalFeatures { + pub name: Symbol, + #[subdiagnostic] + pub note: Option, +} + #[derive(Subdiagnostic)] #[help(lint_help)] pub struct BuiltinIncompleteFeaturesHelp; #[derive(Subdiagnostic)] #[note(lint_note)] -pub struct BuiltinIncompleteFeaturesNote { +pub struct BuiltinFeatureIssueNote { pub n: NonZeroU32, } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7e3b6e9e218..1a612731808 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3925,7 +3925,6 @@ declare_lint! { /// /// // in crate B /// #![feature(non_exhaustive_omitted_patterns_lint)] - /// /// match Bar::A { /// Bar::A => {}, /// #[warn(non_exhaustive_omitted_patterns)] diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 904f8eb5731..f4593d0fe73 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -7,6 +7,7 @@ #![allow(rustc::default_hash_types)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![recursion_limit = "128"] use synstructure::decl_derive; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 1b125e8e26d..f5576b59571 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -64,6 +64,7 @@ #![feature(macro_metavar_expr)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate bitflags; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 6712db26693..892be36aae7 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -8,6 +8,7 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 4cf0f1305a7..53005ede843 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -11,6 +11,7 @@ #![allow(rustc::potential_query_instability, unused_parens)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index da5e92a075a..e403386e60c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -18,6 +18,7 @@ #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] #![allow(rustc::potential_query_instability)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d57aa820fcb..a270817f310 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -10,6 +10,7 @@ #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index fbd9bf05528..afee5c0fe2b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -23,6 +23,7 @@ #![feature(round_char_boundary)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 3307244a217..b52002b1239 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -19,6 +19,7 @@ #![feature(step_trait)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c2655d68b79..1a6a253f360 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -6,6 +6,7 @@ #![feature(unwrap_infallible)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[macro_use] extern crate bitflags; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 967ad3a0e69..80681a7a7cf 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -88,6 +88,7 @@ #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] #![warn(multiple_supertrait_upcastable)] +#![cfg_attr(not(bootstrap), allow(internal_features))] // // Library features: // tidy-alphabetical-start diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 5944a0de1a4..036edbebbf3 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -14,6 +14,7 @@ //! //! ```rust //! #![feature(core_intrinsics, custom_mir)] +#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")] //! //! use core::intrinsics::mir::*; //! @@ -63,6 +64,7 @@ //! //! ```rust //! #![feature(core_intrinsics, custom_mir)] +#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")] //! //! use core::intrinsics::mir::*; //! @@ -315,6 +317,7 @@ define!( /// # Examples /// /// ```rust + #[cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")] /// #![feature(custom_mir, core_intrinsics)] /// /// use core::intrinsics::mir::*; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 37216d6a721..ded799160bf 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -96,6 +96,7 @@ #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] #![warn(multiple_supertrait_upcastable)] +#![cfg_attr(not(bootstrap), allow(internal_features))] // // Library features: // tidy-alphabetical-start diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index b193d79b0e1..76b35919658 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -14,6 +14,7 @@ #![feature(staged_api)] #![feature(rustc_attrs)] #![feature(c_unwind)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[cfg(target_os = "android")] mod android; diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index ce78ab82ef9..2e5459321a2 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -26,6 +26,7 @@ #![feature(c_unwind)] // `real_imp` is unused with Miri, so silence warnings. #![cfg_attr(miri, allow(dead_code))] +#![cfg_attr(not(bootstrap), allow(internal_features))] use alloc::boxed::Box; use core::any::Any; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 2c0d113dbc5..be89afa32b3 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -33,6 +33,7 @@ #![feature(min_specialization)] #![feature(strict_provenance)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(internal_features))] #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] diff --git a/library/profiler_builtins/src/lib.rs b/library/profiler_builtins/src/lib.rs index 0c83bcee06f..a81d0a63547 100644 --- a/library/profiler_builtins/src/lib.rs +++ b/library/profiler_builtins/src/lib.rs @@ -7,4 +7,5 @@ issue = "none" )] #![allow(unused_features)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(staged_api)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 238c74229cc..2f9cd7bc0ca 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -220,6 +220,7 @@ #![warn(missing_debug_implementations)] #![allow(explicit_outlives_requirements)] #![allow(unused_lifetimes)] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![deny(rustc::existing_doc_keyword)] #![deny(fuzzy_provenance_casts)] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 0bd447552cf..64d10dd5712 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -21,6 +21,7 @@ #![feature(process_exitcode_internals)] #![feature(panic_can_unwind)] #![feature(test)] +#![cfg_attr(not(bootstrap), allow(internal_features))] // Public reexports pub use self::bench::{black_box, Bencher}; diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index b655bae9673..0b4daeafe46 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -5,6 +5,7 @@ #![feature(c_unwind)] #![feature(cfg_target_abi)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] +#![cfg_attr(not(bootstrap), allow(internal_features))] cfg_if::cfg_if! { if #[cfg(target_env = "msvc")] { diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 013b93e0129..f69156b7c05 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -200,6 +200,7 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example: ```rust #![feature(rustdoc_internals)] +#![allow(internal_features)] /// Some documentation about the keyword. #[doc(keyword = "keyword")] diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index ea9bace6dd4..8fa8f567d7e 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -17,6 +17,7 @@ via a declaration like ```rust #![feature(intrinsics)] +#![allow(internal_features)] # fn main() {} extern "rust-intrinsic" { diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index f4bc18bc7da..1f3d472c3aa 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -17,6 +17,7 @@ sugar for dynamic allocations via `malloc` and `free`: ```rust,ignore (libc-is-finicky) #![feature(lang_items, start, libc, core_intrinsics, rustc_private, rustc_attrs)] +#![allow(internal_features)] #![no_std] use core::intrinsics; use core::panic::PanicInfo; @@ -119,6 +120,7 @@ in the same format as C: ```rust,ignore (libc-is-finicky) #![feature(lang_items, core_intrinsics, rustc_private)] #![feature(start)] +#![allow(internal_features)] #![no_std] use core::intrinsics; use core::panic::PanicInfo; @@ -155,6 +157,7 @@ compiler's name mangling too: ```rust,ignore (libc-is-finicky) #![feature(lang_items, core_intrinsics, rustc_private)] #![feature(start)] +#![allow(internal_features)] #![no_std] #![no_main] use core::intrinsics; diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 385e25ce6b8..e46f8bf6fab 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -140,6 +140,7 @@ fn base_config(test_dir: &str) -> compiletest::Config { [ "--emit=metadata", "-Aunused", + "-Ainternal_features", "-Zui-testing", "-Dwarnings", &format!("-Ldependency={}", deps_path.display()), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 45582ddcbaf..7aa86c66bad 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -868,6 +868,8 @@ impl<'test> TestCx<'test> { .args(&["--target", &self.config.target]) .arg("-L") .arg(&aux_dir) + .arg("-A") + .arg("internal_features") .args(&self.props.compile_flags) .envs(self.props.rustc_env.clone()); self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags); @@ -936,7 +938,9 @@ impl<'test> TestCx<'test> { .arg("-L") .arg(&self.config.build_base) .arg("-L") - .arg(aux_dir); + .arg(aux_dir) + .arg("-A") + .arg("internal_features"); self.set_revision_flags(&mut rustc); self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags); rustc.args(&self.props.compile_flags); @@ -1867,6 +1871,8 @@ impl<'test> TestCx<'test> { .arg("--deny") .arg("warnings") .arg(&self.testpaths.file) + .arg("-A") + .arg("internal_features") .args(&self.props.compile_flags); if self.config.mode == RustdocJson { @@ -2459,6 +2465,9 @@ impl<'test> TestCx<'test> { rustc.args(&["-A", "unused"]); } + // Allow tests to use internal features. + rustc.args(&["-A", "internal_features"]); + if self.props.force_host { self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags); if !is_rustdoc { diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index fa17923446f..5c3a194214b 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -53,6 +53,7 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> // Add some flags we always want. program.args.push("-Dwarnings".into()); program.args.push("-Dunused".into()); + program.args.push("-Ainternal_features".into()); if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { program.args.push(flag.into()); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 7ad8f5c5c05..d900c04c124 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -338,6 +338,7 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) { Some("active") => Status::Unstable, Some("incomplete") => Status::Unstable, + Some("internal") => Status::Unstable, Some("removed") => Status::Removed, Some("accepted") => Status::Stable, _ => continue, diff --git a/tests/run-make/tools.mk b/tests/run-make/tools.mk index ea06b620c4c..6121a91e920 100644 --- a/tests/run-make/tools.mk +++ b/tests/run-make/tools.mk @@ -8,7 +8,7 @@ TARGET_RPATH_ENV = \ RUSTC_ORIGINAL := $(RUSTC) BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)' BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' -RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) +RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) -Ainternal_features RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR) ifdef RUSTC_LINKER RUSTC := $(RUSTC) -Clinker='$(RUSTC_LINKER)' diff --git a/tests/rustdoc-gui/src/staged_api/lib.rs b/tests/rustdoc-gui/src/staged_api/lib.rs index 5934593a899..0c914470e28 100644 --- a/tests/rustdoc-gui/src/staged_api/lib.rs +++ b/tests/rustdoc-gui/src/staged_api/lib.rs @@ -1,4 +1,5 @@ #![feature(staged_api)] +#![allow(internal_features)] #![stable(feature = "some_feature", since = "1.3.5")] #[stable(feature = "some_feature", since = "1.3.5")] diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index ecf3a7cc147..49484ee0869 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -3,6 +3,7 @@ #![doc(html_playground_url="https://play.rust-lang.org/")] #![crate_name = "test_docs"] +#![allow(internal_features)] #![feature(rustdoc_internals)] #![feature(doc_cfg)] #![feature(associated_type_defaults)] diff --git a/tests/rustdoc/issue-18199.rs b/tests/rustdoc/issue-18199.rs index bc0c4a56502..9cc58b162f3 100644 --- a/tests/rustdoc/issue-18199.rs +++ b/tests/rustdoc/issue-18199.rs @@ -3,6 +3,7 @@ #![doc(test(attr(feature(staged_api))))] /// ``` +/// #![allow(internal_features)] /// #![unstable(feature="test", issue="18199")] /// fn main() {} /// ``` diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs index dce94c9eab2..134ea25b75a 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs @@ -1,7 +1,7 @@ // edition:2018 -#![forbid(incomplete_features, unsafe_code)] +#![forbid(internal_features, unsafe_code)] #![feature(unsafe_pin_internals)] -//~^ ERROR the feature `unsafe_pin_internals` is incomplete and may not be safe to use +//~^ ERROR the feature `unsafe_pin_internals` is internal to the compiler or standard library use core::{marker::PhantomPinned, pin::Pin}; diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr index 4d0c931b404..39afbf2db7e 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr +++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr @@ -1,14 +1,15 @@ -error: the feature `unsafe_pin_internals` is incomplete and may not be safe to use and/or cause compiler crashes +error: the feature `unsafe_pin_internals` is internal to the compiler or standard library --> $DIR/feature-gate-unsafe_pin_internals.rs:3:12 | LL | #![feature(unsafe_pin_internals)] | ^^^^^^^^^^^^^^^^^^^^ | + = note: using it is strongly discouraged note: the lint level is defined here --> $DIR/feature-gate-unsafe_pin_internals.rs:2:11 | -LL | #![forbid(incomplete_features, unsafe_code)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![forbid(internal_features, unsafe_code)] + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error 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 52/62] 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 2c51ed5408e..bdefc41c9c7 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; From 74826462510f4017a463b484fe16ec2da9c2be97 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Thu, 3 Aug 2023 15:12:18 +0100 Subject: [PATCH 53/62] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 020651c5225..d78bbf4bde3 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 020651c52257052d28f6fd83fbecf5cfa1ed516c +Subproject commit d78bbf4bde3c6b95caca7512f537c6f9721426ff From c98c51236da467f877070df7c80dcb603249ce47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 3 Aug 2023 14:38:10 +0000 Subject: [PATCH 54/62] strip librustc_driver.so even at stage 1 --- src/bootstrap/compile.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c7c1f3be2e9..34f19803de0 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -898,13 +898,11 @@ impl Step for Rustc { // unexpected debuginfo from dependencies, for example from the C++ standard library used in // our LLVM wrapper. Unless we're explicitly requesting `librustc_driver` to be built with // debuginfo (via the debuginfo level of the executables using it): strip this debuginfo - // away after the fact. This is to make the distributed artifacts smaller, and therefore we - // only do this at stage >= 1. + // away after the fact. // FIXME: to make things simpler for now, limit this to the host and target where we know // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not // cross-compiling. Expand this to other appropriate targets in the future. - if compiler.stage != 0 - && builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None + if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None && builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None && target == "x86_64-unknown-linux-gnu" && target == builder.config.build From 2fd4c28ed79872e1dff902d92b954b9c591367a6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Apr 2023 01:09:36 +0000 Subject: [PATCH 55/62] Negative test for inlining ` as Fn<()>>::call` --- .../inline/inline_box_fn.call.Inline.diff | 32 +++++++++++++++++++ tests/mir-opt/inline/inline_box_fn.rs | 7 ++++ 2 files changed, 39 insertions(+) create mode 100644 tests/mir-opt/inline/inline_box_fn.call.Inline.diff create mode 100644 tests/mir-opt/inline/inline_box_fn.rs diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff new file mode 100644 index 00000000000..4fa04b05e89 --- /dev/null +++ b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff @@ -0,0 +1,32 @@ +- // MIR for `call` before Inline ++ // MIR for `call` after Inline + + fn call(_1: Box) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: &std::boxed::Box; + let mut _4: (i32,); + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = &_1; + StorageLive(_4); + _4 = (const 1_i32,); + _2 = as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + _0 = const (); + drop(_1) -> [return: bb2, unwind unreachable]; + } + + bb2: { + return; + } + } + diff --git a/tests/mir-opt/inline/inline_box_fn.rs b/tests/mir-opt/inline/inline_box_fn.rs new file mode 100644 index 00000000000..c5a74012098 --- /dev/null +++ b/tests/mir-opt/inline/inline_box_fn.rs @@ -0,0 +1,7 @@ +// unit-test: Inline +// compile-flags: --crate-type=lib + +// EMIT_MIR inline_box_fn.call.Inline.diff +fn call(x: Box) { + x(1); +} From 0391af0e1f617f184d77bbbc093c6595aafab85e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 30 Jun 2023 03:09:02 +0000 Subject: [PATCH 56/62] Only unpack tupled args in inliner if we expect args to be unpacked --- compiler/rustc_mir_transform/src/inline.rs | 15 +++--- ..._ice_on_generic_rust_call.call.Inline.diff | 46 +++++++++++++++++++ .../inline/dont_ice_on_generic_rust_call.rs | 10 ++++ .../inline/inline_box_fn.call.Inline.diff | 30 +++++++++--- 4 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff create mode 100644 tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index f13c8214af1..8abd549c588 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -222,20 +222,23 @@ impl<'tcx> Inliner<'tcx> { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } - if callsite.fn_sig.abi() == Abi::RustCall { - let (arg_tuple, skipped_args) = match &args[..] { - [arg_tuple] => (arg_tuple, 0), - [_, arg_tuple] => (arg_tuple, 1), + if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() { + let (self_arg, arg_tuple) = match &args[..] { + [arg_tuple] => (None, arg_tuple), + [self_arg, arg_tuple] => (Some(self_arg), arg_tuple), _ => bug!("Expected `rust-call` to have 1 or 2 args"), }; + let self_arg_ty = + self_arg.map(|self_arg| self_arg.ty(&caller_body.local_decls, self.tcx)); + let arg_tuple_ty = arg_tuple.ty(&caller_body.local_decls, self.tcx); - let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else { + let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else { bug!("Closure arguments are not passed as a tuple"); }; for (arg_ty, input) in - arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args)) + self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) { diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff new file mode 100644 index 00000000000..c665d779e61 --- /dev/null +++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff @@ -0,0 +1,46 @@ +- // MIR for `call` before Inline ++ // MIR for `call` after Inline + + fn call(_1: Box>, _2: I) -> () { + debug mock => _1; + debug input => _2; + let mut _0: (); + let mut _3: &mut std::boxed::Box>; + let mut _4: I; ++ scope 1 (inlined > as FnMut>::call_mut) { ++ debug self => _3; ++ debug args => _4; ++ let mut _5: &mut dyn std::ops::FnMut; ++ let mut _6: std::boxed::Box>; ++ let mut _7: *const dyn std::ops::FnMut; ++ } + + bb0: { + StorageLive(_3); + _3 = &mut _1; + StorageLive(_4); + _4 = move _2; +- _0 = > as FnMut>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _6 = deref_copy (*_3); ++ _7 = (((_6.0: std::ptr::Unique>).0: std::ptr::NonNull>).0: *const dyn std::ops::FnMut); ++ _5 = &mut (*_7); ++ _0 = as FnMut>::call_mut(move _5, move _4) -> [return: bb2, unwind unreachable]; + } + + bb1: { +- StorageDead(_4); +- StorageDead(_3); +- drop(_1) -> [return: bb2, unwind unreachable]; ++ return; + } + + bb2: { +- return; ++ StorageDead(_5); ++ StorageDead(_4); ++ StorageDead(_3); ++ drop(_1) -> [return: bb1, unwind unreachable]; + } + } + diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs new file mode 100644 index 00000000000..f00e99c27e4 --- /dev/null +++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zmir-enable-passes=+Inline --crate-type=lib + +#![feature(fn_traits, tuple_trait, unboxed_closures)] + +use std::marker::Tuple; + +// EMIT_MIR dont_ice_on_generic_rust_call.call.Inline.diff +pub fn call(mut mock: Box>, input: I) { + mock.call_mut(input) +} diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff index 4fa04b05e89..34ac637af8a 100644 --- a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff +++ b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff @@ -7,6 +7,13 @@ let _2: (); let mut _3: &std::boxed::Box; let mut _4: (i32,); ++ scope 1 (inlined as Fn<(i32,)>>::call) { ++ debug self => _3; ++ debug args => _4; ++ let mut _5: &dyn std::ops::Fn(i32); ++ let mut _6: std::boxed::Box; ++ let mut _7: *const dyn std::ops::Fn(i32); ++ } bb0: { StorageLive(_2); @@ -14,19 +21,30 @@ _3 = &_1; StorageLive(_4); _4 = (const 1_i32,); - _2 = as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable]; +- _2 = as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _6 = deref_copy (*_3); ++ _7 = (((_6.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const dyn std::ops::Fn(i32)); ++ _5 = &(*_7); ++ _2 = >::call(move _5, move _4) -> [return: bb2, unwind unreachable]; } bb1: { ++ return; ++ } ++ ++ bb2: { ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); StorageDead(_2); _0 = const (); - drop(_1) -> [return: bb2, unwind unreachable]; - } - - bb2: { - return; +- drop(_1) -> [return: bb2, unwind unreachable]; +- } +- +- bb2: { +- return; ++ drop(_1) -> [return: bb1, unwind unreachable]; } } From 3c9549b349a2168182035e7a7ae0022d36d63e43 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 30 Jun 2023 21:40:47 +0000 Subject: [PATCH 57/62] Explicitly don't inline user-written rust-call fns --- compiler/rustc_mir_transform/src/inline.rs | 9 +++- .../inline/cycle.g.Inline.panic-abort.diff | 8 +--- .../inline/cycle.g.Inline.panic-unwind.diff | 20 ++++----- .../inline/cycle.main.Inline.panic-abort.diff | 18 +------- .../cycle.main.Inline.panic-unwind.diff | 30 ++++---------- ..._ice_on_generic_rust_call.call.Inline.diff | 27 +++--------- .../inline/inline_box_fn.call.Inline.diff | 30 +++----------- .../inline_cycle.two.Inline.panic-abort.diff | 18 +------- .../inline_cycle.two.Inline.panic-unwind.diff | 18 +------- ...inline_diverging.h.Inline.panic-abort.diff | 24 +++++++---- ...nline_diverging.h.Inline.panic-unwind.diff | 40 ++++++++++++++---- .../issue_78442.bar.Inline.panic-abort.diff | 20 +++------ .../issue_78442.bar.Inline.panic-unwind.diff | 41 ++++++------------- 13 files changed, 102 insertions(+), 201 deletions(-) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 8abd549c588..fc9e18378d5 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -222,7 +222,14 @@ impl<'tcx> Inliner<'tcx> { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } - if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() { + if callsite.fn_sig.abi() == Abi::RustCall { + // FIXME: Don't inline user-written `extern "rust-call"` functions, + // since this is generally perf-negative on rustc, and we hope that + // LLVM will inline these functions instead. + if callee_body.spread_arg.is_some() { + return Err("do not inline user-written rust-call functions"); + } + let (self_arg, arg_tuple) = match &args[..] { [arg_tuple] => (None, arg_tuple), [self_arg, arg_tuple] => (Some(self_arg), arg_tuple), diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff index f3f4d895ae2..8f2baf4a3b6 100644 --- a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff @@ -5,13 +5,10 @@ let mut _0: (); let _1: (); + let mut _2: fn() {main}; -+ let mut _5: (); + scope 1 (inlined f::) { + debug g => _2; + let mut _3: &fn() {main}; + let _4: (); -+ scope 2 (inlined >::call - shim(fn() {main})) { -+ } + } bb0: { @@ -22,9 +19,7 @@ + StorageLive(_4); + StorageLive(_3); + _3 = &_2; -+ StorageLive(_5); -+ _5 = const (); -+ _4 = move (*_3)() -> [return: bb2, unwind unreachable]; ++ _4 = >::call(move _3, const ()) -> [return: bb2, unwind unreachable]; } bb1: { @@ -36,7 +31,6 @@ + } + + bb2: { -+ StorageDead(_5); + StorageDead(_3); + drop(_2) -> [return: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff index 3ce8d9acf36..ad801fd280a 100644 --- a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff @@ -5,13 +5,10 @@ let mut _0: (); let _1: (); + let mut _2: fn() {main}; -+ let mut _5: (); + scope 1 (inlined f::) { + debug g => _2; + let mut _3: &fn() {main}; + let _4: (); -+ scope 2 (inlined >::call - shim(fn() {main})) { -+ } + } bb0: { @@ -22,9 +19,7 @@ + StorageLive(_4); + StorageLive(_3); + _3 = &_2; -+ StorageLive(_5); -+ _5 = const (); -+ _4 = move (*_3)() -> [return: bb4, unwind: bb2]; ++ _4 = >::call(move _3, const ()) -> [return: bb2, unwind: bb3]; } bb1: { @@ -35,18 +30,17 @@ return; + } + -+ bb2 (cleanup): { -+ drop(_2) -> [return: bb3, unwind terminate]; ++ bb2: { ++ StorageDead(_3); ++ drop(_2) -> [return: bb1, unwind continue]; + } + + bb3 (cleanup): { -+ resume; ++ drop(_2) -> [return: bb4, unwind terminate]; + } + -+ bb4: { -+ StorageDead(_5); -+ StorageDead(_3); -+ drop(_2) -> [return: bb1, unwind continue]; ++ bb4 (cleanup): { ++ resume; } } diff --git a/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff b/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff index eb007635416..fd1f698c60d 100644 --- a/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff @@ -5,21 +5,10 @@ let mut _0: (); let _1: (); + let mut _2: fn() {g}; -+ let mut _5: (); + scope 1 (inlined f::) { + debug g => _2; + let mut _3: &fn() {g}; + let _4: (); -+ scope 2 (inlined >::call - shim(fn() {g})) { -+ scope 3 (inlined g) { -+ scope 4 (inlined f::) { -+ debug g => main; -+ let _6: (); -+ scope 5 (inlined >::call - shim(fn() {main})) { -+ } -+ } -+ } -+ } + } bb0: { @@ -30,10 +19,7 @@ + StorageLive(_4); + StorageLive(_3); + _3 = &_2; -+ StorageLive(_5); -+ _5 = const (); -+ StorageLive(_6); -+ _6 = main() -> [return: bb2, unwind unreachable]; ++ _4 = >::call(move _3, const ()) -> [return: bb2, unwind unreachable]; } bb1: { @@ -45,8 +31,6 @@ + } + + bb2: { -+ StorageDead(_6); -+ StorageDead(_5); + StorageDead(_3); + drop(_2) -> [return: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff index 198a2322618..99dc64115a9 100644 --- a/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff @@ -5,21 +5,10 @@ let mut _0: (); let _1: (); + let mut _2: fn() {g}; -+ let mut _5: (); + scope 1 (inlined f::) { + debug g => _2; + let mut _3: &fn() {g}; + let _4: (); -+ scope 2 (inlined >::call - shim(fn() {g})) { -+ scope 3 (inlined g) { -+ scope 4 (inlined f::) { -+ debug g => main; -+ let _6: (); -+ scope 5 (inlined >::call - shim(fn() {main})) { -+ } -+ } -+ } -+ } + } bb0: { @@ -30,10 +19,7 @@ + StorageLive(_4); + StorageLive(_3); + _3 = &_2; -+ StorageLive(_5); -+ _5 = const (); -+ StorageLive(_6); -+ _6 = main() -> [return: bb4, unwind: bb2]; ++ _4 = >::call(move _3, const ()) -> [return: bb2, unwind: bb3]; } bb1: { @@ -44,19 +30,17 @@ return; + } + -+ bb2 (cleanup): { -+ drop(_2) -> [return: bb3, unwind terminate]; ++ bb2: { ++ StorageDead(_3); ++ drop(_2) -> [return: bb1, unwind continue]; + } + + bb3 (cleanup): { -+ resume; ++ drop(_2) -> [return: bb4, unwind terminate]; + } + -+ bb4: { -+ StorageDead(_6); -+ StorageDead(_5); -+ StorageDead(_3); -+ drop(_2) -> [return: bb1, unwind continue]; ++ bb4 (cleanup): { ++ resume; } } diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff index c665d779e61..757617e5940 100644 --- a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff +++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff @@ -7,40 +7,23 @@ let mut _0: (); let mut _3: &mut std::boxed::Box>; let mut _4: I; -+ scope 1 (inlined > as FnMut>::call_mut) { -+ debug self => _3; -+ debug args => _4; -+ let mut _5: &mut dyn std::ops::FnMut; -+ let mut _6: std::boxed::Box>; -+ let mut _7: *const dyn std::ops::FnMut; -+ } bb0: { StorageLive(_3); _3 = &mut _1; StorageLive(_4); _4 = move _2; -- _0 = > as FnMut>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ StorageLive(_5); -+ _6 = deref_copy (*_3); -+ _7 = (((_6.0: std::ptr::Unique>).0: std::ptr::NonNull>).0: *const dyn std::ops::FnMut); -+ _5 = &mut (*_7); -+ _0 = as FnMut>::call_mut(move _5, move _4) -> [return: bb2, unwind unreachable]; + _0 = > as FnMut>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable]; } bb1: { -- StorageDead(_4); -- StorageDead(_3); -- drop(_1) -> [return: bb2, unwind unreachable]; -+ return; + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb2, unwind unreachable]; } bb2: { -- return; -+ StorageDead(_5); -+ StorageDead(_4); -+ StorageDead(_3); -+ drop(_1) -> [return: bb1, unwind unreachable]; + return; } } diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff index 34ac637af8a..4fa04b05e89 100644 --- a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff +++ b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff @@ -7,13 +7,6 @@ let _2: (); let mut _3: &std::boxed::Box; let mut _4: (i32,); -+ scope 1 (inlined as Fn<(i32,)>>::call) { -+ debug self => _3; -+ debug args => _4; -+ let mut _5: &dyn std::ops::Fn(i32); -+ let mut _6: std::boxed::Box; -+ let mut _7: *const dyn std::ops::Fn(i32); -+ } bb0: { StorageLive(_2); @@ -21,30 +14,19 @@ _3 = &_1; StorageLive(_4); _4 = (const 1_i32,); -- _2 = as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ StorageLive(_5); -+ _6 = deref_copy (*_3); -+ _7 = (((_6.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const dyn std::ops::Fn(i32)); -+ _5 = &(*_7); -+ _2 = >::call(move _5, move _4) -> [return: bb2, unwind unreachable]; + _2 = as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable]; } bb1: { -+ return; -+ } -+ -+ bb2: { -+ StorageDead(_5); StorageDead(_4); StorageDead(_3); StorageDead(_2); _0 = const (); -- drop(_1) -> [return: bb2, unwind unreachable]; -- } -- -- bb2: { -- return; -+ drop(_1) -> [return: bb1, unwind unreachable]; + drop(_1) -> [return: bb2, unwind unreachable]; + } + + bb2: { + return; } } diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff index d83c8d585ea..8a6eec3352a 100644 --- a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff @@ -5,20 +5,9 @@ let mut _0: (); let _1: (); + let mut _2: fn() {f}; -+ let mut _4: (); + scope 1 (inlined call::) { + debug f => _2; + let _3: (); -+ scope 2 (inlined >::call_once - shim(fn() {f})) { -+ scope 3 (inlined f) { -+ scope 4 (inlined call::) { -+ debug f => f; -+ let _5: (); -+ scope 5 (inlined >::call_once - shim(fn() {f})) { -+ } -+ } -+ } -+ } + } bb0: { @@ -27,15 +16,10 @@ + StorageLive(_2); + _2 = f; + StorageLive(_3); -+ StorageLive(_4); -+ _4 = const (); -+ StorageLive(_5); -+ _5 = f() -> [return: bb1, unwind unreachable]; ++ _3 = >::call_once(move _2, const ()) -> [return: bb1, unwind unreachable]; } bb1: { -+ StorageDead(_5); -+ StorageDead(_4); + StorageDead(_3); + StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff index a08662959dd..a24649c1ebd 100644 --- a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff @@ -5,20 +5,9 @@ let mut _0: (); let _1: (); + let mut _2: fn() {f}; -+ let mut _4: (); + scope 1 (inlined call::) { + debug f => _2; + let _3: (); -+ scope 2 (inlined >::call_once - shim(fn() {f})) { -+ scope 3 (inlined f) { -+ scope 4 (inlined call::) { -+ debug f => f; -+ let _5: (); -+ scope 5 (inlined >::call_once - shim(fn() {f})) { -+ } -+ } -+ } -+ } + } bb0: { @@ -27,15 +16,10 @@ + StorageLive(_2); + _2 = f; + StorageLive(_3); -+ StorageLive(_4); -+ _4 = const (); -+ StorageLive(_5); -+ _5 = f() -> [return: bb1, unwind continue]; ++ _3 = >::call_once(move _2, const ()) -> [return: bb1, unwind continue]; } bb1: { -+ StorageDead(_5); -+ StorageDead(_4); + StorageDead(_3); + StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff index 0dcd5fae88d..7d5553b2f37 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff @@ -5,7 +5,6 @@ let mut _0: (); let _1: (!, !); + let mut _2: fn() -> ! {sleep}; -+ let mut _7: (); + scope 1 (inlined call_twice:: ! {sleep}>) { + debug f => _2; + let mut _3: &fn() -> ! {sleep}; @@ -18,10 +17,6 @@ + debug b => _6; + } + } -+ scope 4 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { -+ scope 5 (inlined sleep) { -+ } -+ } + } bb0: { @@ -33,13 +28,24 @@ + StorageLive(_6); + StorageLive(_3); + _3 = &_2; -+ StorageLive(_7); -+ _7 = const (); -+ goto -> bb1; ++ _4 = ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind unreachable]; + } + + bb1: { -+ goto -> bb1; ++ StorageDead(_3); ++ StorageLive(_5); ++ _5 = &_2; ++ _6 = ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind unreachable]; ++ } ++ ++ bb2: { ++ StorageDead(_5); ++ _1 = (move _4, move _6); ++ drop(_2) -> [return: bb3, unwind unreachable]; ++ } ++ ++ bb3: { ++ unreachable; } } diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff index dfc12db12a8..073ddeff7ca 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff @@ -5,7 +5,6 @@ let mut _0: (); let _1: (!, !); + let mut _2: fn() -> ! {sleep}; -+ let mut _8: (); + scope 1 (inlined call_twice:: ! {sleep}>) { + debug f => _2; + let mut _3: &fn() -> ! {sleep}; @@ -19,10 +18,6 @@ + debug b => _6; + } + } -+ scope 4 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { -+ scope 5 (inlined sleep) { -+ } -+ } + } bb0: { @@ -34,13 +29,40 @@ + StorageLive(_4); + StorageLive(_3); + _3 = &_2; -+ StorageLive(_8); -+ _8 = const (); -+ goto -> bb1; ++ _4 = ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind: bb5]; + } + + bb1: { -+ goto -> bb1; ++ StorageDead(_3); ++ StorageLive(_5); ++ _5 = &_2; ++ _6 = ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind: bb4]; ++ } ++ ++ bb2: { ++ StorageDead(_5); ++ StorageLive(_7); ++ _7 = move _4; ++ _1 = (move _7, move _6); ++ StorageDead(_7); ++ StorageDead(_4); ++ drop(_2) -> [return: bb3, unwind continue]; ++ } ++ ++ bb3: { ++ unreachable; ++ } ++ ++ bb4 (cleanup): { ++ drop(_4) -> [return: bb5, unwind terminate]; ++ } ++ ++ bb5 (cleanup): { ++ drop(_2) -> [return: bb6, unwind terminate]; ++ } ++ ++ bb6 (cleanup): { ++ resume; } } diff --git a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff index b86eb5f35c9..bee01a5f97b 100644 --- a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff @@ -8,8 +8,6 @@ let mut _3: &fn() {foo}; let _4: fn() {foo}; let mut _5: (); -+ scope 1 (inlined >::call - shim(fn() {foo})) { -+ } bb0: { StorageLive(_2); @@ -22,26 +20,20 @@ _3 = &_4; StorageLive(_5); _5 = (); -- _2 = >::call(move _3, move _5) -> [return: bb2, unwind unreachable]; -+ _2 = move (*_3)() -> [return: bb3, unwind unreachable]; + _2 = >::call(move _3, move _5) -> [return: bb2, unwind unreachable]; } bb2: { -+ return; -+ } -+ -+ bb3: { StorageDead(_5); StorageDead(_3); StorageDead(_4); StorageDead(_2); _0 = const (); -- drop(_1) -> [return: bb3, unwind unreachable]; -- } -- -- bb3: { -- return; -+ drop(_1) -> [return: bb2, unwind unreachable]; + drop(_1) -> [return: bb3, unwind unreachable]; + } + + bb3: { + return; } } diff --git a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff index c67babba23e..b750330df92 100644 --- a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff @@ -8,55 +8,40 @@ let mut _3: &fn() {foo}; let _4: fn() {foo}; let mut _5: (); -+ scope 1 (inlined >::call - shim(fn() {foo})) { -+ } bb0: { StorageLive(_2); StorageLive(_3); StorageLive(_4); -- _4 = hide_foo() -> [return: bb1, unwind: bb4]; -+ _4 = hide_foo() -> [return: bb1, unwind: bb3]; + _4 = hide_foo() -> [return: bb1, unwind: bb4]; } bb1: { _3 = &_4; StorageLive(_5); _5 = (); -- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; -+ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; + _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; } bb2: { -- StorageDead(_5); -- StorageDead(_3); -- StorageDead(_4); -- StorageDead(_2); -- _0 = const (); -- drop(_1) -> [return: bb3, unwind: bb5]; -+ return; + StorageDead(_5); + StorageDead(_3); + StorageDead(_4); + StorageDead(_2); + _0 = const (); + drop(_1) -> [return: bb3, unwind: bb5]; } -- bb3: { -- return; -+ bb3 (cleanup): { -+ drop(_1) -> [return: bb4, unwind terminate]; + bb3: { + return; } bb4 (cleanup): { -- drop(_1) -> [return: bb5, unwind terminate]; -+ resume; + drop(_1) -> [return: bb5, unwind terminate]; } -- bb5 (cleanup): { -- resume; -+ bb5: { -+ StorageDead(_5); -+ StorageDead(_3); -+ StorageDead(_4); -+ StorageDead(_2); -+ _0 = const (); -+ drop(_1) -> [return: bb2, unwind: bb4]; + bb5 (cleanup): { + resume; } } From e43649fdc3946558a94a7ab57d399413fc2bb2b5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Jul 2023 16:22:21 +0000 Subject: [PATCH 58/62] bless --- ...ic_rust_call.call.Inline.panic-abort.diff} | 0 ...ic_rust_call.call.Inline.panic-unwind.diff | 37 +++++++++++++++++ .../inline/dont_ice_on_generic_rust_call.rs | 1 + ...nline_box_fn.call.Inline.panic-abort.diff} | 0 ...nline_box_fn.call.Inline.panic-unwind.diff | 40 +++++++++++++++++++ tests/mir-opt/inline/inline_box_fn.rs | 1 + 6 files changed, 79 insertions(+) rename tests/mir-opt/inline/{dont_ice_on_generic_rust_call.call.Inline.diff => dont_ice_on_generic_rust_call.call.Inline.panic-abort.diff} (100%) create mode 100644 tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff rename tests/mir-opt/inline/{inline_box_fn.call.Inline.diff => inline_box_fn.call.Inline.panic-abort.diff} (100%) create mode 100644 tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-abort.diff similarity index 100% rename from tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff rename to tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-abort.diff diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff new file mode 100644 index 00000000000..ef85e075eeb --- /dev/null +++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff @@ -0,0 +1,37 @@ +- // MIR for `call` before Inline ++ // MIR for `call` after Inline + + fn call(_1: Box>, _2: I) -> () { + debug mock => _1; + debug input => _2; + let mut _0: (); + let mut _3: &mut std::boxed::Box>; + let mut _4: I; + + bb0: { + StorageLive(_3); + _3 = &mut _1; + StorageLive(_4); + _4 = move _2; + _0 = > as FnMut>::call_mut(move _3, move _4) -> [return: bb1, unwind: bb3]; + } + + bb1: { + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb2, unwind: bb4]; + } + + bb2: { + return; + } + + bb3 (cleanup): { + drop(_1) -> [return: bb4, unwind terminate]; + } + + bb4 (cleanup): { + resume; + } + } + diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs index f00e99c27e4..971223c72ca 100644 --- a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs +++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs @@ -1,3 +1,4 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // compile-flags: -Zmir-enable-passes=+Inline --crate-type=lib #![feature(fn_traits, tuple_trait, unboxed_closures)] diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-abort.diff similarity index 100% rename from tests/mir-opt/inline/inline_box_fn.call.Inline.diff rename to tests/mir-opt/inline/inline_box_fn.call.Inline.panic-abort.diff diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff new file mode 100644 index 00000000000..5df730a9930 --- /dev/null +++ b/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff @@ -0,0 +1,40 @@ +- // MIR for `call` before Inline ++ // MIR for `call` after Inline + + fn call(_1: Box) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: &std::boxed::Box; + let mut _4: (i32,); + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = &_1; + StorageLive(_4); + _4 = (const 1_i32,); + _2 = as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; + } + + bb1: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + _0 = const (); + drop(_1) -> [return: bb2, unwind: bb4]; + } + + bb2: { + return; + } + + bb3 (cleanup): { + drop(_1) -> [return: bb4, unwind terminate]; + } + + bb4 (cleanup): { + resume; + } + } + diff --git a/tests/mir-opt/inline/inline_box_fn.rs b/tests/mir-opt/inline/inline_box_fn.rs index c5a74012098..348f0e77f92 100644 --- a/tests/mir-opt/inline/inline_box_fn.rs +++ b/tests/mir-opt/inline/inline_box_fn.rs @@ -1,3 +1,4 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: Inline // compile-flags: --crate-type=lib From f15832f44433685faab7364b0b325baa33188d39 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 3 Aug 2023 20:43:28 +0200 Subject: [PATCH 59/62] compiletest: Handle non-utf8 paths (fix FIXME) --- src/tools/compiletest/src/runtest.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 45582ddcbaf..640efa78796 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1933,7 +1933,8 @@ impl<'test> TestCx<'test> { let mut test_client = Command::new(self.config.remote_test_client.as_ref().unwrap()); test_client - .args(&["run", &support_libs.len().to_string(), &prog]) + .args(&["run", &support_libs.len().to_string()]) + .arg(&prog) .args(support_libs) .args(args); @@ -2516,7 +2517,7 @@ impl<'test> TestCx<'test> { // If this is emscripten, then run tests under nodejs if self.config.target.contains("emscripten") { if let Some(ref p) = self.config.nodejs { - args.push(p.clone()); + args.push(p.into()); } else { self.fatal("emscripten target requested and no NodeJS binary found (--nodejs)"); } @@ -2524,7 +2525,7 @@ impl<'test> TestCx<'test> { // shim } else if self.config.target.contains("wasm32") { if let Some(ref p) = self.config.nodejs { - args.push(p.clone()); + args.push(p.into()); } else { self.fatal("wasm32 target requested and no NodeJS binary found (--nodejs)"); } @@ -2536,13 +2537,12 @@ impl<'test> TestCx<'test> { .unwrap() // chop off `ui` .parent() .unwrap(); // chop off `tests` - args.push(src.join("src/etc/wasm32-shim.js").display().to_string()); + args.push(src.join("src/etc/wasm32-shim.js").into_os_string()); } let exe_file = self.make_exe_name(); - // FIXME (#9639): This needs to handle non-utf8 paths - args.push(exe_file.to_str().unwrap().to_owned()); + args.push(exe_file.into_os_string()); // Add the arguments in the run_flags directive args.extend(self.split_maybe_args(&self.props.run_flags)); @@ -2551,12 +2551,16 @@ impl<'test> TestCx<'test> { ProcArgs { prog, args } } - fn split_maybe_args(&self, argstr: &Option) -> Vec { + fn split_maybe_args(&self, argstr: &Option) -> Vec { match *argstr { Some(ref s) => s .split(' ') .filter_map(|s| { - if s.chars().all(|c| c.is_whitespace()) { None } else { Some(s.to_owned()) } + if s.chars().all(|c| c.is_whitespace()) { + None + } else { + Some(OsString::from(s)) + } }) .collect(), None => Vec::new(), @@ -4363,8 +4367,8 @@ impl<'test> TestCx<'test> { } struct ProcArgs { - prog: String, - args: Vec, + prog: OsString, + args: Vec, } pub struct ProcRes { From 40729bcb6914c8d239c70ad9ac4c532a0d12e495 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 3 Aug 2023 12:48:55 -0700 Subject: [PATCH 60/62] Enable tests on rustc_codegen_ssa --- compiler/rustc_codegen_ssa/Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 6582fd62387..8f383f68bcd 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -3,9 +3,6 @@ name = "rustc_codegen_ssa" version = "0.0.0" edition = "2021" -[lib] -test = false - [dependencies] ar_archive_writer = "0.1.3" bitflags = "1.2.1" From 2232fe8da3dcd4796e6db060ba61ba9c70a2a3f5 Mon Sep 17 00:00:00 2001 From: xstaticxgpx Date: Wed, 2 Aug 2023 09:58:30 -0400 Subject: [PATCH 61/62] unix/kernel_copy.rs: copy_file_range_candidate allows empty output files This is for https://github.com/rust-lang/rust/issues/114341 The `meta.len() > 0` condition here is intended for inputs only, ie. when input is in the `/proc` filesystem as documented. That inaccurately included empty output files which are then shunted to the sendfile() routine leading to higher than nescessary IO util in some cases, specifically with CoW filesystems like btrfs. Further, `NoneObtained` is not relevant in this context, so remove it. Simply, determine what is input or output given the passed enum Unit. --- library/std/src/sys/unix/kernel_copy.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 7d49bbdcbe0..4d17a1b0002 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -89,6 +89,12 @@ enum FdMeta { NoneObtained, } +#[derive(PartialEq)] +enum FdHandle { + Input, + Output, +} + impl FdMeta { fn maybe_fifo(&self) -> bool { match self { @@ -114,12 +120,14 @@ impl FdMeta { } } - fn copy_file_range_candidate(&self) -> bool { + fn copy_file_range_candidate(&self, f: FdHandle) -> bool { match self { // copy_file_range will fail on empty procfs files. `read` can determine whether EOF has been reached // without extra cost and skip the write, thus there is no benefit in attempting copy_file_range - FdMeta::Metadata(meta) if meta.is_file() && meta.len() > 0 => true, - FdMeta::NoneObtained => true, + FdMeta::Metadata(meta) if f == FdHandle::Input && meta.is_file() && meta.len() > 0 => { + true + } + FdMeta::Metadata(meta) if f == FdHandle::Output && meta.is_file() => true, _ => false, } } @@ -197,7 +205,9 @@ impl SpecCopy for Copier<'_, '_, R, W> { written += flush()?; let max_write = reader.min_limit(); - if input_meta.copy_file_range_candidate() && output_meta.copy_file_range_candidate() { + if input_meta.copy_file_range_candidate(FdHandle::Input) + && output_meta.copy_file_range_candidate(FdHandle::Output) + { let result = copy_regular_files(readfd, writefd, max_write); result.update_take(reader); From 325dc9288e1d15a9d25ec040ef8a568f46de505b Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Fri, 4 Aug 2023 05:27:12 +0000 Subject: [PATCH 62/62] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b3e184cb216..f195bd5ac8a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -d8bbef50bbad789e26219f4ec88b5d73b05570a3 \ No newline at end of file +a7caaae9fbef81325887aea060fc551da4589c6f \ No newline at end of file