From 3efe0174a24421e4ff300c805d47be7ae7aa5981 Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Mon, 24 May 2021 11:41:39 +0800 Subject: [PATCH 01/30] shrinking the deprecated method span --- compiler/rustc_passes/src/stability.rs | 10 +- .../ui/deprecation/deprecation-lint.stderr | 108 ++++++++--------- src/test/ui/deprecation/suggestion.fixed | 17 ++- src/test/ui/deprecation/suggestion.rs | 17 ++- src/test/ui/deprecation/suggestion.stderr | 18 ++- .../ui/lint/lint-stability-deprecated.stderr | 112 +++++++++--------- .../generics-default-stability.stderr | 16 +-- 7 files changed, 167 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index f41e0e037068..2a09311bbdb4 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -828,7 +828,15 @@ impl Visitor<'tcx> for Checker<'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) { if let Some(def_id) = path.res.opt_def_id() { - self.tcx.check_stability(def_id, Some(id), path.span, None) + let method_span = if path.segments.len() >= 2 { + match path.segments.last() { + Some(s) => Some(s.ident.span), + None => None, + } + } else { + None + }; + self.tcx.check_stability(def_id, Some(id), path.span, method_span) } intravisit::walk_path(self, path) } diff --git a/src/test/ui/deprecation/deprecation-lint.stderr b/src/test/ui/deprecation/deprecation-lint.stderr index 3699a939e278..20af4f62e650 100644 --- a/src/test/ui/deprecation/deprecation-lint.stderr +++ b/src/test/ui/deprecation/deprecation-lint.stderr @@ -11,16 +11,16 @@ LL | #![deny(deprecated)] | ^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:21:9 + --> $DIR/deprecation-lint.rs:21:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:23:9 + --> $DIR/deprecation-lint.rs:23:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated function `deprecation_lint::deprecated_text`: text --> $DIR/deprecation-lint.rs:25:9 @@ -29,16 +29,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:30:9 + --> $DIR/deprecation-lint.rs:30:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:32:9 + --> $DIR/deprecation-lint.rs:32:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::DeprecatedStruct`: text --> $DIR/deprecation-lint.rs:34:17 @@ -53,10 +53,10 @@ LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated variant `deprecation_lint::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:40:17 + --> $DIR/deprecation-lint.rs:40:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::DeprecatedTupleStruct`: text --> $DIR/deprecation-lint.rs:42:17 @@ -65,28 +65,28 @@ LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::nested::DeprecatedStruct`: text - --> $DIR/deprecation-lint.rs:44:17 + --> $DIR/deprecation-lint.rs:44:25 | LL | let _ = nested::DeprecatedStruct { - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::nested::DeprecatedUnitStruct`: text - --> $DIR/deprecation-lint.rs:48:17 + --> $DIR/deprecation-lint.rs:48:25 | LL | let _ = nested::DeprecatedUnitStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated variant `deprecation_lint::nested::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:50:17 + --> $DIR/deprecation-lint.rs:50:31 | LL | ... let _ = nested::Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::nested::DeprecatedTupleStruct`: text - --> $DIR/deprecation-lint.rs:52:17 + --> $DIR/deprecation-lint.rs:52:25 | LL | ... let _ = nested::DeprecatedTupleStruct (1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated function `deprecation_lint::deprecated_text`: text --> $DIR/deprecation-lint.rs:59:25 @@ -101,28 +101,28 @@ LL | macro_test_arg!(macro_test_arg!(deprecated_text())); | ^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:65:9 + --> $DIR/deprecation-lint.rs:65:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:67:9 + --> $DIR/deprecation-lint.rs:67:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:69:9 + --> $DIR/deprecation-lint.rs:69:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:71:9 + --> $DIR/deprecation-lint.rs:71:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated trait `deprecation_lint::DeprecatedTrait`: text --> $DIR/deprecation-lint.rs:81:10 @@ -173,10 +173,10 @@ LL | let Deprecated2 | ^^^^^^^^^^^ error: use of deprecated function `deprecation_lint::deprecated_mod::deprecated`: text - --> $DIR/deprecation-lint.rs:162:9 + --> $DIR/deprecation-lint.rs:162:25 | LL | deprecated_mod::deprecated(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: use of deprecated function `this_crate::deprecated`: text --> $DIR/deprecation-lint.rs:245:9 @@ -185,16 +185,16 @@ LL | deprecated(); | ^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:250:9 + --> $DIR/deprecation-lint.rs:250:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:252:9 + --> $DIR/deprecation-lint.rs:252:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated function `this_crate::deprecated_text`: text --> $DIR/deprecation-lint.rs:254:9 @@ -203,16 +203,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:259:9 + --> $DIR/deprecation-lint.rs:259:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:261:9 + --> $DIR/deprecation-lint.rs:261:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated function `this_crate::deprecated_future`: text --> $DIR/deprecation-lint.rs:264:9 @@ -239,10 +239,10 @@ LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:274:17 + --> $DIR/deprecation-lint.rs:274:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text --> $DIR/deprecation-lint.rs:276:17 @@ -251,52 +251,52 @@ LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated struct `this_crate::nested::DeprecatedStruct`: text - --> $DIR/deprecation-lint.rs:278:17 + --> $DIR/deprecation-lint.rs:278:25 | LL | let _ = nested::DeprecatedStruct { - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text - --> $DIR/deprecation-lint.rs:283:17 + --> $DIR/deprecation-lint.rs:283:25 | LL | let _ = nested::DeprecatedUnitStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated unit variant `this_crate::nested::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:285:17 + --> $DIR/deprecation-lint.rs:285:31 | LL | ... let _ = nested::Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated tuple struct `this_crate::nested::DeprecatedTupleStruct`: text - --> $DIR/deprecation-lint.rs:287:17 + --> $DIR/deprecation-lint.rs:287:25 | LL | ... let _ = nested::DeprecatedTupleStruct (1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:292:9 + --> $DIR/deprecation-lint.rs:292:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:294:9 + --> $DIR/deprecation-lint.rs:294:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:296:9 + --> $DIR/deprecation-lint.rs:296:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:298:9 + --> $DIR/deprecation-lint.rs:298:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` --> $DIR/deprecation-lint.rs:316:13 diff --git a/src/test/ui/deprecation/suggestion.fixed b/src/test/ui/deprecation/suggestion.fixed index eba72f88a891..1ba1821e6c18 100644 --- a/src/test/ui/deprecation/suggestion.fixed +++ b/src/test/ui/deprecation/suggestion.fixed @@ -1,9 +1,7 @@ // run-rustfix #![feature(staged_api)] - #![stable(since = "1.0.0", feature = "test")] - #![deny(deprecated)] #![allow(dead_code)] @@ -21,8 +19,21 @@ impl Foo { fn replacement(&self) {} } +mod bar { + #[rustc_deprecated( + since = "1.0.0", + reason = "replaced by `replacement`", + suggestion = "replacement", + )] + #[stable(since = "1.0.0", feature = "test")] + pub fn deprecated() {} + + pub fn replacement() {} +} + fn main() { let foo = Foo; - foo.replacement(); //~ ERROR use of deprecated + + bar::replacement(); //~ ERROR use of deprecated } diff --git a/src/test/ui/deprecation/suggestion.rs b/src/test/ui/deprecation/suggestion.rs index 8f9791c13e85..e40737d19575 100644 --- a/src/test/ui/deprecation/suggestion.rs +++ b/src/test/ui/deprecation/suggestion.rs @@ -1,9 +1,7 @@ // run-rustfix #![feature(staged_api)] - #![stable(since = "1.0.0", feature = "test")] - #![deny(deprecated)] #![allow(dead_code)] @@ -21,8 +19,21 @@ impl Foo { fn replacement(&self) {} } +mod bar { + #[rustc_deprecated( + since = "1.0.0", + reason = "replaced by `replacement`", + suggestion = "replacement", + )] + #[stable(since = "1.0.0", feature = "test")] + pub fn deprecated() {} + + pub fn replacement() {} +} + fn main() { let foo = Foo; - foo.deprecated(); //~ ERROR use of deprecated + + bar::deprecated(); //~ ERROR use of deprecated } diff --git a/src/test/ui/deprecation/suggestion.stderr b/src/test/ui/deprecation/suggestion.stderr index 8a7cb1def909..b95ca3a75e46 100644 --- a/src/test/ui/deprecation/suggestion.stderr +++ b/src/test/ui/deprecation/suggestion.stderr @@ -1,14 +1,20 @@ -error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement` - --> $DIR/suggestion.rs:27:9 +error: use of deprecated function `bar::deprecated`: replaced by `replacement` + --> $DIR/suggestion.rs:38:10 | -LL | foo.deprecated(); - | ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement` +LL | bar::deprecated(); + | ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement` | note: the lint level is defined here - --> $DIR/suggestion.rs:7:9 + --> $DIR/suggestion.rs:5:9 | LL | #![deny(deprecated)] | ^^^^^^^^^^ -error: aborting due to previous error +error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement` + --> $DIR/suggestion.rs:36:9 + | +LL | foo.deprecated(); + | ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement` + +error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/lint-stability-deprecated.stderr b/src/test/ui/lint/lint-stability-deprecated.stderr index 94fc1a7b46db..4b082fcd3595 100644 --- a/src/test/ui/lint/lint-stability-deprecated.stderr +++ b/src/test/ui/lint/lint-stability-deprecated.stderr @@ -11,16 +11,16 @@ LL | #![warn(deprecated)] | ^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:29:9 + --> $DIR/lint-stability-deprecated.rs:29:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:31:9 + --> $DIR/lint-stability-deprecated.rs:31:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated function `lint_stability::deprecated_text`: text --> $DIR/lint-stability-deprecated.rs:33:9 @@ -29,16 +29,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:38:9 + --> $DIR/lint-stability-deprecated.rs:38:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:40:9 + --> $DIR/lint-stability-deprecated.rs:40:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated function `lint_stability::deprecated_unstable`: text --> $DIR/lint-stability-deprecated.rs:42:9 @@ -47,16 +47,16 @@ LL | deprecated_unstable(); | ^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:47:9 + --> $DIR/lint-stability-deprecated.rs:47:16 | LL | ... Trait::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:49:9 + --> $DIR/lint-stability-deprecated.rs:49:25 | LL | ... ::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated function `lint_stability::deprecated_unstable_text`: text --> $DIR/lint-stability-deprecated.rs:51:9 @@ -65,16 +65,16 @@ LL | deprecated_unstable_text(); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:56:9 + --> $DIR/lint-stability-deprecated.rs:56:16 | LL | ... Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:58:9 + --> $DIR/lint-stability-deprecated.rs:58:25 | LL | ... ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated struct `lint_stability::DeprecatedStruct`: text --> $DIR/lint-stability-deprecated.rs:108:17 @@ -101,16 +101,16 @@ LL | let _ = DeprecatedUnstableUnitStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated variant `lint_stability::Enum::DeprecatedVariant`: text - --> $DIR/lint-stability-deprecated.rs:123:17 + --> $DIR/lint-stability-deprecated.rs:123:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ warning: use of deprecated variant `lint_stability::Enum::DeprecatedUnstableVariant`: text - --> $DIR/lint-stability-deprecated.rs:124:17 + --> $DIR/lint-stability-deprecated.rs:124:23 | LL | let _ = Enum::DeprecatedUnstableVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated struct `lint_stability::DeprecatedTupleStruct`: text --> $DIR/lint-stability-deprecated.rs:128:17 @@ -143,52 +143,52 @@ LL | macro_test_arg!(macro_test_arg!(deprecated_text())); | ^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:145:9 + --> $DIR/lint-stability-deprecated.rs:145:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:147:9 + --> $DIR/lint-stability-deprecated.rs:147:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:149:9 + --> $DIR/lint-stability-deprecated.rs:149:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:151:9 + --> $DIR/lint-stability-deprecated.rs:151:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:153:9 + --> $DIR/lint-stability-deprecated.rs:153:16 | LL | ... Trait::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:155:9 + --> $DIR/lint-stability-deprecated.rs:155:25 | LL | ... ::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:157:9 + --> $DIR/lint-stability-deprecated.rs:157:16 | LL | ... Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:159:9 + --> $DIR/lint-stability-deprecated.rs:159:25 | LL | ... ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated trait `lint_stability::DeprecatedTrait`: text --> $DIR/lint-stability-deprecated.rs:187:10 @@ -203,10 +203,10 @@ LL | trait LocalTrait2 : DeprecatedTrait { } | ^^^^^^^^^^^^^^^ warning: use of deprecated function `inheritance::inherited_stability::unstable_mod::deprecated`: text - --> $DIR/lint-stability-deprecated.rs:208:9 + --> $DIR/lint-stability-deprecated.rs:208:23 | LL | unstable_mod::deprecated(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ warning: use of deprecated function `this_crate::deprecated`: text --> $DIR/lint-stability-deprecated.rs:330:9 @@ -215,16 +215,16 @@ LL | deprecated(); | ^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:335:9 + --> $DIR/lint-stability-deprecated.rs:335:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:337:9 + --> $DIR/lint-stability-deprecated.rs:337:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated function `this_crate::deprecated_text`: text --> $DIR/lint-stability-deprecated.rs:339:9 @@ -233,16 +233,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:344:9 + --> $DIR/lint-stability-deprecated.rs:344:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:346:9 + --> $DIR/lint-stability-deprecated.rs:346:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated struct `this_crate::DeprecatedStruct`: text --> $DIR/lint-stability-deprecated.rs:384:17 @@ -257,10 +257,10 @@ LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text - --> $DIR/lint-stability-deprecated.rs:395:17 + --> $DIR/lint-stability-deprecated.rs:395:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ warning: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text --> $DIR/lint-stability-deprecated.rs:399:17 @@ -269,28 +269,28 @@ LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:406:9 + --> $DIR/lint-stability-deprecated.rs:406:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:408:9 + --> $DIR/lint-stability-deprecated.rs:408:25 | LL | ::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:410:9 + --> $DIR/lint-stability-deprecated.rs:410:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:412:9 + --> $DIR/lint-stability-deprecated.rs:412:25 | LL | ... ::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated function `this_crate::test_fn_body::fn_in_body`: text --> $DIR/lint-stability-deprecated.rs:439:9 diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 99523f8eb645..c3e3f543d799 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -169,10 +169,10 @@ LL | let _: Alias5 = Alias5::Some(0); | ^^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test - --> $DIR/generics-default-stability.rs:231:27 + --> $DIR/generics-default-stability.rs:231:34 | LL | let _: Enum4 = Enum4::Some(1); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum4`: test --> $DIR/generics-default-stability.rs:231:12 @@ -193,10 +193,10 @@ LL | let _: Enum4 = ENUM4; | ^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test - --> $DIR/generics-default-stability.rs:237:27 + --> $DIR/generics-default-stability.rs:237:34 | LL | let _: Enum4 = Enum4::Some(0); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum4`: test --> $DIR/generics-default-stability.rs:237:12 @@ -205,10 +205,10 @@ LL | let _: Enum4 = Enum4::Some(0); | ^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test - --> $DIR/generics-default-stability.rs:242:27 + --> $DIR/generics-default-stability.rs:242:34 | LL | let _: Enum5 = Enum5::Some(1); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum5`: test --> $DIR/generics-default-stability.rs:242:12 @@ -229,10 +229,10 @@ LL | let _: Enum5 = ENUM5; | ^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test - --> $DIR/generics-default-stability.rs:249:27 + --> $DIR/generics-default-stability.rs:249:34 | LL | let _: Enum5 = Enum5::Some(0); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum5`: test --> $DIR/generics-default-stability.rs:249:12 From c180af8e30bc815118ac3efe633f7cf8870465da Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Tue, 25 May 2021 00:33:41 +0800 Subject: [PATCH 02/30] Address comment --- compiler/rustc_passes/src/stability.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 2a09311bbdb4..c6c165544a94 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -829,10 +829,7 @@ impl Visitor<'tcx> for Checker<'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) { if let Some(def_id) = path.res.opt_def_id() { let method_span = if path.segments.len() >= 2 { - match path.segments.last() { - Some(s) => Some(s.ident.span), - None => None, - } + path.segments.last().map(|s| s.ident.span) } else { None }; From 027d73dcad10c5d70a313809ff584fc8f054b6a8 Mon Sep 17 00:00:00 2001 From: Roxane Date: Tue, 25 May 2021 18:30:54 -0400 Subject: [PATCH 03/30] Restrict Fake Read precision --- compiler/rustc_typeck/src/check/upvar.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 71e222c560a0..6baa185406e2 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1588,6 +1588,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) { if let PlaceBase::Upvar(_) = place.base { + // We need to restrict Fake Read precision to avoid fake reading unsafe code, + // such as deref of a raw pointer. + let place = restrict_capture_precision(place); + let place = + restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place); self.fake_reads.push((place, cause, diag_expr_id)); } } From 382338fe755a4300358ae17a5df211236c257a27 Mon Sep 17 00:00:00 2001 From: Roxane Date: Thu, 27 May 2021 17:58:35 -0400 Subject: [PATCH 04/30] Remove feature gate --- .../src/build/expr/as_rvalue.rs | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 2185bd3a5c61..69786c14ee8d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -186,25 +186,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // }; // ``` // - // FIXME(RFC2229, rust#85435): Remove feature gate once diagnostics are - // improved and unsafe checking works properly in closure bodies again. - if this.tcx.features().capture_disjoint_fields { - for (thir_place, cause, hir_id) in fake_reads.into_iter() { - let place_builder = - unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); - - if let Ok(place_builder_resolved) = - place_builder.try_upvars_resolved(this.tcx, this.typeck_results) - { - let mir_place = - place_builder_resolved.into_place(this.tcx, this.typeck_results); - this.cfg.push_fake_read( - block, - this.source_info(this.tcx.hir().span(*hir_id)), - *cause, - mir_place, - ); - } + for (thir_place, cause, hir_id) in fake_reads.into_iter() { + let place_builder = + unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); + + if let Ok(place_builder_resolved) = + place_builder.try_upvars_resolved(this.tcx, this.typeck_results) + { + let mir_place = + place_builder_resolved.into_place(this.tcx, this.typeck_results); + this.cfg.push_fake_read( + block, + this.source_info(this.tcx.hir().span(*hir_id)), + *cause, + mir_place, + ); } } From 7fed92b3a4fd8b219fe576c60d31342b193cd92d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 6 May 2021 07:50:40 -0700 Subject: [PATCH 05/30] rustc: Allow safe #[target_feature] on wasm This commit updates the compiler's handling of the `#[target_feature]` attribute when applied to functions on WebAssembly-based targets. The compiler in general requires that any functions with `#[target_feature]` are marked as `unsafe` as well, but this commit relaxes the restriction for WebAssembly targets where the attribute can be applied to safe functions as well. The reason this is done is that the motivation for this feature of the compiler is not applicable for WebAssembly targets. In general the `#[target_feature]` attribute is used to enhance target CPU features enabled beyond the basic level for the rest of the compilation. If done improperly this means that your program could execute an instruction that the CPU you happen to be running on does not understand. This is considered undefined behavior where it is unknown what will happen (e.g. it's not a deterministic `SIGILL`). For WebAssembly, however, the target is different. It is not possible for a running WebAssembly program to execute an instruction that the engine does not understand. If this were the case then the program would not have validated in the first place and would not run at all. Even if this were allowed in some hypothetical future where engines have some form of runtime feature detection (which they do not right now) any implementation of such a feature would generate a trap if a module attempts to execute an instruction the module does not understand. This deterministic trap behavior would still not fall into the category of undefined behavior because the trap is deterministic. For these reasons the `#[target_feature]` attribute is now allowed on safe functions, but only for WebAssembly targets. This notably enables the wasm-SIMD intrinsics proposed for stabilization in #74372 to be marked as safe generally instead of today where they're all `unsafe` due to the historical implementation of `#[target_feature]` in the compiler. --- .../rustc_mir/src/transform/check_unsafety.rs | 6 +++ .../rustc_mir_build/src/check_unsafety.rs | 17 ++++--- compiler/rustc_typeck/src/collect.rs | 16 ++++++- src/test/ui/target-feature/wasm-safe.rs | 44 +++++++++++++++++++ 4 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/target-feature/wasm-safe.rs diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index 955be8cc81e1..9a4e51203d2b 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -376,6 +376,12 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether /// the called function has target features the calling function hasn't. fn check_target_features(&mut self, func_did: DefId) { + // Unsafety isn't required on wasm targets. For more information see + // the corresponding check in typeck/src/collect.rs + if self.tcx.sess.target.options.is_like_wasm { + return; + } + let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 971b6dd9e1c8..91a8c601db95 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -166,13 +166,16 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.requires_unsafe(expr.span, CallToUnsafeFunction); } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() { // If the called function has target features the calling function hasn't, - // the call requires `unsafe`. - if !self - .tcx - .codegen_fn_attrs(func_did) - .target_features - .iter() - .all(|feature| self.body_target_features.contains(feature)) + // the call requires `unsafe`. Don't check this on wasm + // targets, though. For more information on wasm see the + // is_like_wasm check in typeck/src/collect.rs + if !self.tcx.sess.target.options.is_like_wasm + && !self + .tcx + .codegen_fn_attrs(func_did) + .target_features + .iter() + .all(|feature| self.body_target_features.contains(feature)) { self.requires_unsafe(expr.span, CallToFunctionWith); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 0528f8812f92..5d83375e5a1b 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2770,7 +2770,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } else if tcx.sess.check_name(attr, sym::target_feature) { if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { - if !tcx.features().target_feature_11 { + if tcx.sess.target.is_like_wasm { + // The `#[target_feature]` attribute is allowed on + // WebAssembly targets on all functions, including safe + // ones. Other targets require that `#[target_feature]` is + // only applied to unsafe funtions (pending the + // `target_feature_11` feature) because on most targets + // execution of instructions that are not supported is + // considered undefined behavior. For WebAssembly which is a + // 100% safe target at execution time it's not possible to + // execute undefined instructions, and even if a future + // feature was added in some form for this it would be a + // deterministic trap. There is no undefined behavior when + // executing WebAssembly so `#[target_feature]` is allowed + // on safe functions (but again, only for WebAssembly) + } else if !tcx.features().target_feature_11 { let mut err = feature_err( &tcx.sess.parse_sess, sym::target_feature_11, diff --git a/src/test/ui/target-feature/wasm-safe.rs b/src/test/ui/target-feature/wasm-safe.rs new file mode 100644 index 000000000000..4b868684a520 --- /dev/null +++ b/src/test/ui/target-feature/wasm-safe.rs @@ -0,0 +1,44 @@ +// only-wasm32 +// check-pass + +#![feature(wasm_target_feature)] +#![allow(dead_code)] + +#[target_feature(enable = "nontrapping-fptoint")] +fn foo() {} + +#[target_feature(enable = "nontrapping-fptoint")] +extern "C" fn bar() {} + +trait A { + fn foo(); + fn bar(&self); +} + +struct B; + +impl B { + #[target_feature(enable = "nontrapping-fptoint")] + fn foo() {} + #[target_feature(enable = "nontrapping-fptoint")] + fn bar(&self) {} +} + +impl A for B { + #[target_feature(enable = "nontrapping-fptoint")] + fn foo() {} + #[target_feature(enable = "nontrapping-fptoint")] + fn bar(&self) {} +} + +fn no_features_enabled_on_this_function() { + bar(); + foo(); + B.bar(); + B::foo(); + ::foo(); + ::bar(&B); +} + +#[target_feature(enable = "nontrapping-fptoint")] +fn main() {} From dbff14b879a1c5c05b34e1a3af5fba192b383a24 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 31 May 2021 13:24:16 +0200 Subject: [PATCH 06/30] Clarify meaning of MachineApplicable suggestions. --- compiler/rustc_lint_defs/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 70475563a4ab..f1c4e5fb4a36 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -25,7 +25,11 @@ macro_rules! pluralize { /// before applying the suggestion. #[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)] pub enum Applicability { - /// The suggestion is definitely what the user intended. This suggestion should be + /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code. + /// This suggestion should be automatically applied. + /// + /// In case of multiple `MachineApplicable` suggestions (whether as part of + /// the same `multipart_suggestion` or not), all of them should be /// automatically applied. MachineApplicable, From a0228d9b877591d2b94484b1ff9d433e6f0a5d32 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 1 Jun 2021 05:04:48 +0200 Subject: [PATCH 07/30] Intra doc link-ify a reference to a function --- library/core/src/num/f32.rs | 4 ++-- library/core/src/num/f64.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 77132cddca27..c47a2e8b05c4 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -727,8 +727,8 @@ impl f32 { /// /// This is currently identical to `transmute::(self)` on all platforms. /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 4c3f1fd16a0d..cfcc08b9adde 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -741,8 +741,8 @@ impl f64 { /// /// This is currently identical to `transmute::(self)` on all platforms. /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. From 92839563506163bc1bfb9d137782649c8b527bb1 Mon Sep 17 00:00:00 2001 From: csmoe Date: Tue, 1 Jun 2021 13:59:17 +0800 Subject: [PATCH 08/30] skip check_static on rvalue::threadlocalref --- .../src/transform/check_consts/validation.rs | 6 ++- src/test/ui/thread-local-static.rs | 16 +++++++ src/test/ui/thread-local-static.stderr | 45 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/thread-local-static.rs create mode 100644 src/test/ui/thread-local-static.stderr diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 41d9d0d04b50..9538d2fdd4da 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -732,7 +732,11 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if proj_base.is_empty() { if let (local, []) = (place_local, proj_base) { let decl = &self.body.local_decls[local]; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + if let Some(box LocalInfo::StaticRef { + def_id, + is_thread_local: false, + }) = decl.local_info + { let span = decl.source_info.span; self.check_static(def_id, span); return; diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs new file mode 100644 index 000000000000..7f4ead36cd0f --- /dev/null +++ b/src/test/ui/thread-local-static.rs @@ -0,0 +1,16 @@ +// edition:2018 + +#![feature(thread_local)] +#![feature(const_swap)] +#[thread_local] +static mut STATIC_VAR_2: [u32; 8] = [4; 8]; +const fn g(x: &mut [u32; 8]) { + //~^ ERROR mutable references are not allowed + std::mem::swap(x, &mut STATIC_VAR_2) + //~^ ERROR thread-local statics cannot be accessed + //~| ERROR dereferencing raw pointers in constant + //~| ERROR mutable references are not allowed + //~| ERROR use of mutable static is unsafe +} + +fn main() {} diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr new file mode 100644 index 000000000000..ed461fcb7e2f --- /dev/null +++ b/src/test/ui/thread-local-static.stderr @@ -0,0 +1,45 @@ +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:7:12 + | +LL | const fn g(x: &mut [u32; 8]) { + | ^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0625]: thread-local statics cannot be accessed at compile-time + --> $DIR/thread-local-static.rs:9:28 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^ + +error[E0658]: dereferencing raw pointers in constant functions is unstable + --> $DIR/thread-local-static.rs:9:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #51911 for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:9:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/thread-local-static.rs:9:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0133, E0658. +For more information about an error, try `rustc --explain E0133`. From ba680aa5f25e1584ef6eb54ed45b35ea6d58f9a7 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 1 Jun 2021 17:44:49 +0100 Subject: [PATCH 09/30] Add test for forward declared const param defaults --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 4 +-- .../defaults/forward-declared.rs | 15 +++++++++++ .../defaults/forward-declared.stderr | 27 +++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/forward-declared.rs create mode 100644 src/test/ui/const-generics/defaults/forward-declared.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index a1eafd65d643..03d94f43897b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -450,7 +450,7 @@ impl<'a> Resolver<'a> { err.span_label(shadowed_binding_span, msg); err } - ResolutionError::ForwardDeclaredTyParam => { + ResolutionError::ForwardDeclaredGenericParam => { let mut err = struct_span_err!( self.session, span, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5e009d148322..dd80b0045967 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -242,7 +242,7 @@ enum ResolutionError<'a> { shadowed_binding_span: Span, }, /// Error E0128: generic parameters with a default cannot use forward-declared identifiers. - ForwardDeclaredTyParam, // FIXME(const_generics_defaults) + ForwardDeclaredGenericParam, /// ERROR E0770: the type of const parameters must not depend on other generic parameters. ParamInTyOfConstParam(Symbol), /// generic parameters must not be used inside const evaluations. @@ -2617,7 +2617,7 @@ impl<'a> Resolver<'a> { let res_error = if rib_ident.name == kw::SelfUpper { ResolutionError::SelfInTyParamDefault } else { - ResolutionError::ForwardDeclaredTyParam + ResolutionError::ForwardDeclaredGenericParam }; self.report_error(span, res_error); } diff --git a/src/test/ui/const-generics/defaults/forward-declared.rs b/src/test/ui/const-generics/defaults/forward-declared.rs new file mode 100644 index 000000000000..09fc105320e4 --- /dev/null +++ b/src/test/ui/const-generics/defaults/forward-declared.rs @@ -0,0 +1,15 @@ +#![feature(const_generics_defaults)] + +struct Foo; +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +enum Bar {} +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +struct Foo2; +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +enum Bar2 {} +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/forward-declared.stderr b/src/test/ui/const-generics/defaults/forward-declared.stderr new file mode 100644 index 000000000000..a6c4a7ae4ef2 --- /dev/null +++ b/src/test/ui/const-generics/defaults/forward-declared.stderr @@ -0,0 +1,27 @@ +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:3:29 + | +LL | struct Foo; + | ^ defaulted generic parameters cannot be forward declared + +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:6:27 + | +LL | enum Bar {} + | ^ defaulted generic parameters cannot be forward declared + +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:9:30 + | +LL | struct Foo2; + | ^ defaulted generic parameters cannot be forward declared + +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:12:28 + | +LL | enum Bar2 {} + | ^ defaulted generic parameters cannot be forward declared + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0128`. From f4f76e60b3c4b0f52caecc5e52f9ee7f24b7d050 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Sat, 1 May 2021 14:56:48 -0700 Subject: [PATCH 10/30] Reland - Report coverage `0` of dead blocks Fixes: #84018 With `-Z instrument-coverage`, coverage reporting of dead blocks (for example, blocks dropped because a conditional branch is dropped, based on const evaluation) is now supported. Note, this PR relands an earlier, reverted PR that failed when compiling generators. The prior issues with generators has been resolved and a new test was added to prevent future regressions. Check out the resulting changes to test coverage of dead blocks in the test coverage reports in this PR. --- .../rustc_codegen_ssa/src/coverageinfo/map.rs | 9 ++ .../rustc_mir/src/transform/const_goto.rs | 2 +- .../src/transform/deduplicate_blocks.rs | 2 +- .../src/transform/early_otherwise_branch.rs | 2 +- compiler/rustc_mir/src/transform/generator.rs | 4 +- compiler/rustc_mir/src/transform/inline.rs | 2 +- .../rustc_mir/src/transform/match_branches.rs | 2 +- .../transform/multiple_return_terminators.rs | 2 +- .../src/transform/remove_unneeded_drops.rs | 2 +- compiler/rustc_mir/src/transform/simplify.rs | 85 +++++++++++++++++-- .../rustc_mir/src/transform/simplify_try.rs | 2 +- .../src/transform/unreachable_prop.rs | 2 +- .../expected_show_coverage.async2.txt | 1 + .../expected_show_coverage.conditions.txt | 8 +- .../expected_show_coverage.doctest.txt | 4 +- .../expected_show_coverage.drop_trait.txt | 10 +-- .../expected_show_coverage.generator.txt | 32 +++++++ .../expected_show_coverage.generics.txt | 18 ++-- .../expected_show_coverage.loops_branches.txt | 38 ++++----- .../expected_show_coverage.tight_inf_loop.txt | 2 +- .../run-make-fulldeps/coverage/conditions.rs | 4 +- .../run-make-fulldeps/coverage/generator.rs | 30 +++++++ .../run-make-fulldeps/coverage/generics.rs | 10 +-- .../coverage/loops_branches.rs | 8 +- 24 files changed, 216 insertions(+), 65 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt create mode 100644 src/test/run-make-fulldeps/coverage/generator.rs diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs index 08442c588f87..c1dfe1ef8560 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs @@ -28,6 +28,7 @@ pub struct Expression { /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count /// for a gap area is only used as the line execution count if there are no other regions on a /// line." +#[derive(Debug)] pub struct FunctionCoverage<'tcx> { instance: Instance<'tcx>, source_hash: u64, @@ -113,6 +114,14 @@ impl<'tcx> FunctionCoverage<'tcx> { expression_id, lhs, op, rhs, region ); let expression_index = self.expression_index(u32::from(expression_id)); + debug_assert!( + expression_index.as_usize() < self.expressions.len(), + "expression_index {} is out of range for expressions.len() = {} + for {:?}", + expression_index.as_usize(), + self.expressions.len(), + self, + ); if let Some(previous_expression) = self.expressions[expression_index].replace(Expression { lhs, op, diff --git a/compiler/rustc_mir/src/transform/const_goto.rs b/compiler/rustc_mir/src/transform/const_goto.rs index b5c8b4bebc36..ba10b54c5ae2 100644 --- a/compiler/rustc_mir/src/transform/const_goto.rs +++ b/compiler/rustc_mir/src/transform/const_goto.rs @@ -47,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(body); + simplify_cfg(tcx, body); simplify_locals(body, tcx); } } diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs index c41e71e09a4e..912505c65983 100644 --- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs +++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs @@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { if has_opts_to_apply { let mut opt_applier = OptApplier { tcx, duplicates }; opt_applier.visit_body(body); - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 7934d4ba8499..07127042fa41 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -164,7 +164,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // Since this optimization adds new basic blocks and invalidates others, // clean up the cfg to make it nicer for other passes if should_cleanup { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 003003a8abbe..3560b4b1e864 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the resume part of the function - simplify::remove_dead_blocks(&mut body); + simplify::remove_dead_blocks(tcx, &mut body); dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(())); @@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(())); } diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index b6f80763bc8c..f1c95a84ade8 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Inline { if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index f7a9835353e5..21b208a08c2d 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -167,7 +167,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } if should_cleanup { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs index 4aaa0baa9f46..cd2db1805528 100644 --- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -38,6 +38,6 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { } } - simplify::remove_dead_blocks(body) + simplify::remove_dead_blocks(tcx, body) } } diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 5144d48750de..02e45021a0aa 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -36,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index 65e2d096b209..7aebca77e6f2 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -29,6 +29,7 @@ use crate::transform::MirPass; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -46,9 +47,9 @@ impl SimplifyCfg { } } -pub fn simplify_cfg(body: &mut Body<'_>) { +pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + remove_dead_blocks(tcx, body); // FIXME: Should probably be moved into some kind of pass manager body.basic_blocks_mut().raw.shrink_to_fit(); @@ -59,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { Cow::Borrowed(&self.label) } - fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source); - simplify_cfg(body); + simplify_cfg(tcx, body); } } @@ -286,7 +287,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } } -pub fn remove_dead_blocks(body: &mut Body<'_>) { +pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks().len(); if num_blocks == reachable.count() { @@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } used_blocks += 1; } + + if tcx.sess.instrument_coverage() { + save_unreachable_coverage(basic_blocks, used_blocks); + } + basic_blocks.raw.truncate(used_blocks); for block in basic_blocks { @@ -315,6 +321,75 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } } +/// Some MIR transforms can determine at compile time that a sequences of +/// statements will never be executed, so they can be dropped from the MIR. +/// For example, an `if` or `else` block that is guaranteed to never be executed +/// because its condition can be evaluated at compile time, such as by const +/// evaluation: `if false { ... }`. +/// +/// Those statements are bypassed by redirecting paths in the CFG around the +/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually +/// include `Coverage` statements representing the Rust source code regions to +/// be counted at runtime. Without these `Coverage` statements, the regions are +/// lost, and the Rust source code will show no coverage information. +/// +/// What we want to show in a coverage report is the dead code with coverage +/// counts of `0`. To do this, we need to save the code regions, by injecting +/// `Unreachable` coverage statements. These are non-executable statements whose +/// code regions are still recorded in the coverage map, representing regions +/// with `0` executions. +fn save_unreachable_coverage( + basic_blocks: &mut IndexVec>, + first_dead_block: usize, +) { + let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| { + live_block.statements.iter().any(|statement| { + if let StatementKind::Coverage(coverage) = &statement.kind { + matches!(coverage.kind, CoverageKind::Counter { .. }) + } else { + false + } + }) + }); + if !has_live_counters { + // If there are no live `Counter` `Coverage` statements anymore, don't + // move dead coverage to the `START_BLOCK`. Just allow the dead + // `Coverage` statements to be dropped with the dead blocks. + // + // The `generator::StateTransform` MIR pass can create atypical + // conditions, where all live `Counter`s are dropped from the MIR. + // + // At least one Counter per function is required by LLVM (and necessary, + // to add the `function_hash` to the counter's call to the LLVM + // intrinsic `instrprof.increment()`). + return; + } + + // Retain coverage info for dead blocks, so coverage reports will still + // report `0` executions for the uncovered code regions. + let mut dropped_coverage = Vec::new(); + for dead_block in basic_blocks.raw[first_dead_block..].iter() { + for statement in dead_block.statements.iter() { + if let StatementKind::Coverage(coverage) = &statement.kind { + if let Some(code_region) = &coverage.code_region { + dropped_coverage.push((statement.source_info, code_region.clone())); + } + } + } + } + + let start_block = &mut basic_blocks[START_BLOCK]; + for (source_info, code_region) in dropped_coverage { + start_block.statements.push(Statement { + source_info, + kind: StatementKind::Coverage(box Coverage { + kind: CoverageKind::Unreachable, + code_region: Some(code_region), + }), + }) + } +} + pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index 89fddc95c98f..dd2ec39c066a 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -558,7 +558,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { if did_remove_blocks { // We have dead blocks now, so remove those. - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index 658c6b6e9db2..e7fb6b4f6b4a 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -60,7 +60,7 @@ impl MirPass<'_> for UnreachablePropagation { } if replaced { - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt index 322f5681b3fd..dc06a485a8fc 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt @@ -12,6 +12,7 @@ 12| 1| if b { 13| 1| println!("non_async_func println in block"); 14| 1| } + ^0 15| 1|} 16| | 17| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt index 656a26597759..2d8a98a5d0c9 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt @@ -5,6 +5,7 @@ 5| 1| if true { 6| 1| countdown = 10; 7| 1| } + ^0 8| | 9| | const B: u32 = 100; 10| 1| let x = if countdown > 7 { @@ -24,6 +25,7 @@ 24| 1| if true { 25| 1| countdown = 10; 26| 1| } + ^0 27| | 28| 1| if countdown > 7 { 29| 1| countdown -= 4; @@ -42,6 +44,7 @@ 41| 1| if true { 42| 1| countdown = 10; 43| 1| } + ^0 44| | 45| 1| if countdown > 7 { 46| 1| countdown -= 4; @@ -54,13 +57,14 @@ 53| | } else { 54| 0| return; 55| | } - 56| | } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal - 57| | // `true` was const-evaluated. The compiler knows the `if` block will be executed. + 56| 0| } + 57| | 58| | 59| 1| let mut countdown = 0; 60| 1| if true { 61| 1| countdown = 1; 62| 1| } + ^0 63| | 64| 1| let z = if countdown > 7 { ^0 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt index 1b6bb9ff8891..7ae0e978808e 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt @@ -9,7 +9,7 @@ 8| 1|//! assert_eq!(1, 1); 9| |//! } else { 10| |//! // this is not! - 11| |//! assert_eq!(1, 2); + 11| 0|//! assert_eq!(1, 2); 12| |//! } 13| 1|//! ``` 14| |//! @@ -84,7 +84,7 @@ 74| 1| if true { 75| 1| assert_eq!(1, 1); 76| | } else { - 77| | assert_eq!(1, 2); + 77| 0| assert_eq!(1, 2); 78| | } 79| 1|} 80| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt index fab5be41901c..fe6a9e93cbf7 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt @@ -19,11 +19,11 @@ 19| 1| if true { 20| 1| println!("Exiting with error..."); 21| 1| return Err(1); - 22| | } - 23| | - 24| | let _ = Firework { strength: 1000 }; - 25| | - 26| | Ok(()) + 22| 0| } + 23| 0| + 24| 0| let _ = Firework { strength: 1000 }; + 25| 0| + 26| 0| Ok(()) 27| 1|} 28| | 29| |// Expected program output: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt new file mode 100644 index 000000000000..0fb3808ff2e3 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt @@ -0,0 +1,32 @@ + 1| |#![feature(generators, generator_trait)] + 2| | + 3| |use std::ops::{Generator, GeneratorState}; + 4| |use std::pin::Pin; + 5| | + 6| |// The following implementation of a function called from a `yield` statement + 7| |// (apparently requiring the Result and the `String` type or constructor) + 8| |// creates conditions where the `generator::StateTransform` MIR transform will + 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic + 10| |// to handle this condition, and still report dead block coverage. + 11| 1|fn get_u32(val: bool) -> Result { + 12| 1| if val { Ok(1) } else { Err(String::from("some error")) } + ^0 + 13| 1|} + 14| | + 15| 1|fn main() { + 16| 1| let is_true = std::env::args().len() == 1; + 17| 1| let mut generator = || { + 18| 1| yield get_u32(is_true); + 19| 1| return "foo"; + 20| 1| }; + 21| | + 22| 1| match Pin::new(&mut generator).resume(()) { + 23| 1| GeneratorState::Yielded(Ok(1)) => {} + 24| 0| _ => panic!("unexpected return from resume"), + 25| | } + 26| 1| match Pin::new(&mut generator).resume(()) { + 27| 1| GeneratorState::Complete("foo") => {} + 28| 0| _ => panic!("unexpected return from resume"), + 29| | } + 30| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt index 7b38ffb87cba..8e8bc0fd1894 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt @@ -52,15 +52,15 @@ 30| 1| if true { 31| 1| println!("Exiting with error..."); 32| 1| return Err(1); - 33| | } // The remaining lines below have no coverage because `if true` (with the constant literal - 34| | // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. - 35| | // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown - 36| | // in other tests, the lines below would have coverage (which would show they had `0` - 37| | // executions, assuming the condition still evaluated to `true`). - 38| | - 39| | let _ = Firework { strength: 1000 }; - 40| | - 41| | Ok(()) + 33| 0| } + 34| 0| + 35| 0| + 36| 0| + 37| 0| + 38| 0| + 39| 0| let _ = Firework { strength: 1000 }; + 40| 0| + 41| 0| Ok(()) 42| 1|} 43| | 44| |// Expected program output: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt index 81d5c7d90346..5d572db7cc60 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt @@ -9,23 +9,23 @@ 9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 10| 1| if true { 11| 1| if false { - 12| | while true { - 13| | } + 12| 0| while true { + 13| 0| } 14| 1| } - 15| 1| write!(f, "error")?; - ^0 - 16| | } else { - 17| | } + 15| 1| write!(f, "cool")?; + ^0 + 16| 0| } else { + 17| 0| } 18| | 19| 10| for i in 0..10 { 20| 10| if true { 21| 10| if false { - 22| | while true {} + 22| 0| while true {} 23| 10| } - 24| 10| write!(f, "error")?; - ^0 - 25| | } else { - 26| | } + 24| 10| write!(f, "cool")?; + ^0 + 25| 0| } else { + 26| 0| } 27| | } 28| 1| Ok(()) 29| 1| } @@ -36,21 +36,21 @@ 34| |impl std::fmt::Display for DisplayTest { 35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 36| 1| if false { - 37| | } else { + 37| 0| } else { 38| 1| if false { - 39| | while true {} + 39| 0| while true {} 40| 1| } - 41| 1| write!(f, "error")?; - ^0 + 41| 1| write!(f, "cool")?; + ^0 42| | } 43| 10| for i in 0..10 { 44| 10| if false { - 45| | } else { + 45| 0| } else { 46| 10| if false { - 47| | while true {} + 47| 0| while true {} 48| 10| } - 49| 10| write!(f, "error")?; - ^0 + 49| 10| write!(f, "cool")?; + ^0 50| | } 51| | } 52| 1| Ok(()) diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt index 5adeef7d0850..2d4c57f451a2 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt @@ -1,6 +1,6 @@ 1| 1|fn main() { 2| 1| if false { - 3| | loop {} + 3| 0| loop {} 4| 1| } 5| 1|} diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make-fulldeps/coverage/conditions.rs index 8a2a0b53e586..057599d1b471 100644 --- a/src/test/run-make-fulldeps/coverage/conditions.rs +++ b/src/test/run-make-fulldeps/coverage/conditions.rs @@ -53,8 +53,8 @@ fn main() { } else { return; } - } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal - // `true` was const-evaluated. The compiler knows the `if` block will be executed. + } + let mut countdown = 0; if true { diff --git a/src/test/run-make-fulldeps/coverage/generator.rs b/src/test/run-make-fulldeps/coverage/generator.rs new file mode 100644 index 000000000000..4319991021e7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/generator.rs @@ -0,0 +1,30 @@ +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +// The following implementation of a function called from a `yield` statement +// (apparently requiring the Result and the `String` type or constructor) +// creates conditions where the `generator::StateTransform` MIR transform will +// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic +// to handle this condition, and still report dead block coverage. +fn get_u32(val: bool) -> Result { + if val { Ok(1) } else { Err(String::from("some error")) } +} + +fn main() { + let is_true = std::env::args().len() == 1; + let mut generator = || { + yield get_u32(is_true); + return "foo"; + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(Ok(1)) => {} + _ => panic!("unexpected return from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected return from resume"), + } +} diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make-fulldeps/coverage/generics.rs index cbeda35d3b8c..18b38868496d 100644 --- a/src/test/run-make-fulldeps/coverage/generics.rs +++ b/src/test/run-make-fulldeps/coverage/generics.rs @@ -30,11 +30,11 @@ fn main() -> Result<(),u8> { if true { println!("Exiting with error..."); return Err(1); - } // The remaining lines below have no coverage because `if true` (with the constant literal - // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. - // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown - // in other tests, the lines below would have coverage (which would show they had `0` - // executions, assuming the condition still evaluated to `true`). + } + + + + let _ = Firework { strength: 1000 }; diff --git a/src/test/run-make-fulldeps/coverage/loops_branches.rs b/src/test/run-make-fulldeps/coverage/loops_branches.rs index 4d9bbad3367f..7116ce47f4b9 100644 --- a/src/test/run-make-fulldeps/coverage/loops_branches.rs +++ b/src/test/run-make-fulldeps/coverage/loops_branches.rs @@ -12,7 +12,7 @@ impl std::fmt::Debug for DebugTest { while true { } } - write!(f, "error")?; + write!(f, "cool")?; } else { } @@ -21,7 +21,7 @@ impl std::fmt::Debug for DebugTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } else { } } @@ -38,7 +38,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } for i in 0..10 { if false { @@ -46,7 +46,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } } Ok(()) From 521d9ab59a211030c71cc55399fc61882adbb0d6 Mon Sep 17 00:00:00 2001 From: csmoe Date: Tue, 1 Jun 2021 22:05:04 +0800 Subject: [PATCH 11/30] convert Rvalue::threadlocalref assertion to delay bug --- .../src/transform/check_consts/validation.rs | 13 ++++--------- src/test/ui/thread-local-static.rs | 2 +- src/test/ui/thread-local-static.stderr | 13 ++++++------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 9538d2fdd4da..0ec022ccf82b 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -356,10 +356,9 @@ impl Validator<'mir, 'tcx> { } fn check_static(&mut self, def_id: DefId, span: Span) { - assert!( - !self.tcx.is_thread_local_static(def_id), - "tls access is checked in `Rvalue::ThreadLocalRef" - ); + if self.tcx.is_thread_local_static(def_id) { + self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef"); + } self.check_op_spanned(ops::StaticAccess, span) } @@ -732,11 +731,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if proj_base.is_empty() { if let (local, []) = (place_local, proj_base) { let decl = &self.body.local_decls[local]; - if let Some(box LocalInfo::StaticRef { - def_id, - is_thread_local: false, - }) = decl.local_info - { + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { let span = decl.source_info.span; self.check_static(def_id, span); return; diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs index 7f4ead36cd0f..c7fee9e6b4c5 100644 --- a/src/test/ui/thread-local-static.rs +++ b/src/test/ui/thread-local-static.rs @@ -8,9 +8,9 @@ const fn g(x: &mut [u32; 8]) { //~^ ERROR mutable references are not allowed std::mem::swap(x, &mut STATIC_VAR_2) //~^ ERROR thread-local statics cannot be accessed - //~| ERROR dereferencing raw pointers in constant //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe + //~| constant functions cannot refer to statics } fn main() {} diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr index ed461fcb7e2f..08bf593a5a74 100644 --- a/src/test/ui/thread-local-static.stderr +++ b/src/test/ui/thread-local-static.stderr @@ -13,14 +13,13 @@ error[E0625]: thread-local statics cannot be accessed at compile-time LL | std::mem::swap(x, &mut STATIC_VAR_2) | ^^^^^^^^^^^^ -error[E0658]: dereferencing raw pointers in constant functions is unstable - --> $DIR/thread-local-static.rs:9:23 +error[E0013]: constant functions cannot refer to statics + --> $DIR/thread-local-static.rs:9:28 | LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | - = note: see issue #51911 for more information - = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that error[E0658]: mutable references are not allowed in constant functions --> $DIR/thread-local-static.rs:9:23 @@ -41,5 +40,5 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) error: aborting due to 5 previous errors -Some errors have detailed explanations: E0133, E0658. -For more information about an error, try `rustc --explain E0133`. +Some errors have detailed explanations: E0013, E0133, E0658. +For more information about an error, try `rustc --explain E0013`. From 3844570baac0d82338022bffaa8694fb64e357c6 Mon Sep 17 00:00:00 2001 From: Denis Merigoux Date: Tue, 1 Jun 2021 14:10:14 +0200 Subject: [PATCH 12/30] Restore the num_def_ids_untracked public function giving the total number of exported symbols for each crate Restored underlying num_def_ids_method Update compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs Changed name to fit with naming convention Co-authored-by: bjorn3 Update compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs Replace regular doc with Rustdoc comment Co-authored-by: Joshua Nelson Clarifies third-party use of num_def_ids_untracked --- compiler/rustc_metadata/src/rmeta/decoder.rs | 4 ++++ compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 706f3f6d8542..59fec58f0a1b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1931,6 +1931,10 @@ impl CrateMetadata { self.root.hash } + fn num_def_ids(&self) -> usize { + self.root.tables.def_keys.size() + } + fn local_def_id(&self, index: DefIndex) -> DefId { DefId { krate: self.cnum, index } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 02d1cf9aec79..dfa82b6c046d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -454,6 +454,13 @@ impl CStore { self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) } + /// Only public-facing way to traverse all the definitions in a non-local crate. + /// Critically useful for this third-party project: https://github.com/hacspec/hacspec. + /// See https://github.com/rust-lang/rust/pull/85889 for context. + pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() + } + pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec { self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect() } From f353cbf1a145603e1f69c2aaaef171dd60ca4c65 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 26 Apr 2021 14:39:57 -0400 Subject: [PATCH 13/30] Generate better debuginfo for directly tagged enums --- .../src/debuginfo/metadata.rs | 9 +++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- .../src/debuginfo/type_names.rs | 8 ++++ src/etc/natvis/intrinsic.natvis | 38 +++++++++++++++++++ src/etc/natvis/libcore.natvis | 17 --------- 5 files changed, 52 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0db6659f8e25..7a44e887c893 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1574,7 +1574,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { MemberDescription { name: if fallback { - String::new() + format!("Variant{}", i.as_u32()) } else { variant_info.variant_name() }, @@ -1886,8 +1886,9 @@ fn describe_enum_variant( // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); let offset = enum_layout.fields.offset(tag_field.as_usize()); + let tag_name = if cx.tcx.sess.target.is_like_msvc { "variant$" } else { "RUST$ENUM$DISR" }; let args = - ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); + (tag_name.to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); (Some(offset), Some(args)) } _ => (None, None), @@ -2062,7 +2063,7 @@ fn prepare_enum_metadata( unsafe { llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), - containing_scope, + None, enum_name.as_ptr().cast(), enum_name.len(), file_metadata, @@ -2437,7 +2438,7 @@ fn create_union_stub( llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), - containing_scope, + Some(containing_scope), union_type_name.as_ptr().cast(), union_type_name.len(), unknown_file_metadata(cx), diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 8b1dcea3fa26..54ef1a284689 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2038,7 +2038,7 @@ extern "C" { pub fn LLVMRustDIBuilderCreateUnionType( Builder: &DIBuilder<'a>, - Scope: &'a DIScope, + Scope: Option<&'a DIScope>, Name: *const c_char, NameLen: size_t, File: &'a DIFile, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index d1bbf74307c6..626c71abf63d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -45,8 +45,16 @@ pub fn push_debuginfo_type_name<'tcx>( ty::Float(float_ty) => output.push_str(float_ty.name_str()), ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), ty::Adt(def, substs) => { + if def.is_enum() && cpp_like_names { + output.push_str("_enum<"); + } + push_item_name(tcx, def.did, qualified, output); push_type_params(tcx, substs, output, visited); + + if def.is_enum() && cpp_like_names { + output.push('>'); + } } ty::Tuple(component_types) => { if cpp_like_names { diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 030892a432b3..45e36f929b4d 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -149,4 +149,42 @@ ... + + + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + + + Variant0 + Variant1 + Variant2 + Variant3 + Variant4 + Variant5 + Variant6 + Variant7 + Variant8 + Variant9 + Variant10 + Variant11 + Variant12 + Variant13 + Variant14 + Variant15 + + diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 9c3c26f59783..17667770520c 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -14,14 +14,6 @@ - - None - Some({__0}) - - __0 - - - None Some({($T1 *)this}) @@ -30,15 +22,6 @@ - - Ok({__0}) - Err({(*($T2*) &__0)}) - - __0 - (*($T2*) &__0) - - - {(void*) pointer} From b644f06326577e0926ddf9896fd702befc7bd43e Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 27 Apr 2021 10:42:06 -0400 Subject: [PATCH 14/30] Resolve EnumTagInfo FIXME --- .../src/debuginfo/metadata.rs | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 7a44e887c893..0ab16473a54a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1507,7 +1507,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, self.layout, variant_info, - NoTag, + None, self_metadata, self.span, ); @@ -1539,13 +1539,13 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { .. } => { let tag_info = if fallback { - RegularTag { + Some(DirectTag { tag_field: Field::from(tag_field), tag_type_metadata: self.tag_type_metadata.unwrap(), - } + }) } else { // This doesn't matter in this case. - NoTag + None }; variants .iter_enumerated() @@ -1606,7 +1606,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info_for(dataful_variant), - OptimizedTag, + Some(NicheTag), self.containing_scope, self.span, ); @@ -1681,7 +1681,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - OptimizedTag, + Some(NicheTag), self_metadata, self.span, ); @@ -1771,14 +1771,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { } } -// FIXME: terminology here should be aligned with `abi::TagEncoding`. -// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`. -// `NoTag` should be removed; users should use `Option` instead. #[derive(Copy, Clone)] enum EnumTagInfo<'ll> { - RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType }, - OptimizedTag, - NoTag, + DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType }, + NicheTag, } #[derive(Copy, Clone)] @@ -1859,7 +1855,7 @@ fn describe_enum_variant( cx: &CodegenCx<'ll, 'tcx>, layout: layout::TyAndLayout<'tcx>, variant: VariantInfo<'_, 'tcx>, - discriminant_info: EnumTagInfo<'ll>, + discriminant_info: Option>, containing_scope: &'ll DIScope, span: Span, ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { @@ -1882,7 +1878,7 @@ fn describe_enum_variant( let (offsets, args) = if use_enum_fallback(cx) { // If this is not a univariant enum, there is also the discriminant field. let (discr_offset, discr_arg) = match discriminant_info { - RegularTag { tag_field, .. } => { + Some(DirectTag { tag_field, .. }) => { // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); let offset = enum_layout.fields.offset(tag_field.as_usize()); @@ -1919,7 +1915,7 @@ fn describe_enum_variant( offsets, args, tag_type_metadata: match discriminant_info { - RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata), + Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata), _ => None, }, span, From 2a025c1a765a593030fc6e80a45f4f1053f15aae Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 28 Apr 2021 16:32:54 -0400 Subject: [PATCH 15/30] Remove fallback for containing scopes This wasn't necessary for msvc and caused issues where different types with the same name such as different instantiations of `Option` would have colliding debuginfo. This confused the debugger which would pick one of the type definitions and use for all types with that name even though they had different layout. --- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0ab16473a54a..af0d95a354b2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1457,7 +1457,6 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> { enum_type: Ty<'tcx>, layout: TyAndLayout<'tcx>, tag_type_metadata: Option<&'ll DIType>, - containing_scope: &'ll DIScope, common_members: Vec>, span: Span, } @@ -1488,11 +1487,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { // This will always find the metadata in the type map. let fallback = use_enum_fallback(cx); - let self_metadata = if fallback { - self.containing_scope - } else { - type_metadata(cx, self.enum_type, self.span) - }; + let self_metadata = type_metadata(cx, self.enum_type, self.span); match self.layout.variants { Variants::Single { index } => { @@ -1607,7 +1602,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { variant, variant_info_for(dataful_variant), Some(NicheTag), - self.containing_scope, + self_metadata, self.span, ); @@ -2085,7 +2080,6 @@ fn prepare_enum_metadata( enum_type, layout, tag_type_metadata: discriminant_type_metadata, - containing_scope, common_members: vec![], span, }), @@ -2238,7 +2232,6 @@ fn prepare_enum_metadata( enum_type, layout, tag_type_metadata: None, - containing_scope, common_members: outer_fields, span, }), From 141546c355f2de7501c1df75dd97229ed350eeb3 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 13 May 2021 16:39:19 -0400 Subject: [PATCH 16/30] Generate better debuginfo for niche-layout enums Previously, we would generate a single struct with the layout of the dataful variant plus an extra field whose name contained the value of the niche (this would only really work for things like `Option<&_>` where we can determine that the `None` case maps to `0` but for enums that have multiple tag only variants, this doesn't work). Now, we generate a union of two structs, one which is the layout of the dataful variant and one which just has a way of reading the discriminant. We also generate an enum which maps the discriminant value to the tag only variants. We also encode information about the range of values which correspond to the dataful variant in the type name and then use natvis to determine which union field we should display to the user. As a result of this change, all niche-layout enums render correctly in WinDbg and Visual Studio! --- .../src/debuginfo/metadata.rs | 199 +++++++++++------- .../src/debuginfo/type_names.rs | 59 +++++- src/etc/natvis/intrinsic.natvis | 14 ++ 3 files changed, 191 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index af0d95a354b2..1f268bd18786 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1594,77 +1594,144 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { ref variants, tag_field, } => { + let calculate_niche_value = |i: VariantIdx| { + if i == dataful_variant { + None + } else { + let value = (i.as_u32() as u128) + .wrapping_sub(niche_variants.start().as_u32() as u128) + .wrapping_add(niche_start); + let value = tag.value.size(cx).truncate(value); + // NOTE(eddyb) do *NOT* remove this assert, until + // we pass the full 128-bit value to LLVM, otherwise + // truncation will be silent and remain undetected. + assert_eq!(value as u64 as u128, value); + Some(value as u64) + } + }; + + // For MSVC, we will generate a union of two structs, one for the dataful variant and one that just points to + // the discriminant field. We also create an enum that contains tag values for the non-dataful variants and + // make the discriminant field that type. We then use natvis to render the enum type correctly in Windbg/VS. if fallback { - let variant = self.layout.for_variant(cx, dataful_variant); - // Create a description of the non-null variant. - let (variant_type_metadata, member_description_factory) = describe_enum_variant( + let unique_type_id = debug_context(cx) + .type_map + .borrow_mut() + .get_unique_type_id_of_enum_variant(cx, self.enum_type, "discriminant$"); + + let variant_metadata = create_struct_stub( + cx, + self.layout.ty, + &"discriminant$", + unique_type_id, + Some(self_metadata), + DIFlags::FlagArtificial, + ); + + let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant); + + let mut discr_enum_ty = tag.value.to_ty(cx.tcx); + // If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr. + // CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up + // to just be `usize`. + if let ty::RawPtr(_) = discr_enum_ty.kind() { + discr_enum_ty = cx.tcx.types.usize; + } + + let tags: Vec<_> = variants + .iter_enumerated() + .filter_map(|(variant_idx, _)| { + calculate_niche_value(variant_idx).map(|tag| { + let variant = variant_info_for(variant_idx); + let name = variant.variant_name(); + + Some(unsafe { + llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr().cast(), + name.len(), + tag as i64, + !discr_enum_ty.is_signed(), + ) + }) + }) + }) + .collect(); + + let discr_enum = unsafe { + llvm::LLVMRustDIBuilderCreateEnumerationType( + DIB(cx), + self_metadata, + "tag$".as_ptr().cast(), + "tag$".len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + tag.value.size(cx).bits(), + tag.value.align(cx).abi.bits() as u32, + create_DIArray(DIB(cx), &tags), + type_metadata(cx, discr_enum_ty, self.span), + true, + ) + }; + + let (size, align) = + cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty); + let members = vec![MemberDescription { + name: "discriminant".to_string(), + type_metadata: discr_enum, + offset: dataful_variant_layout.fields.offset(tag_field), + size, + align, + flags: DIFlags::FlagArtificial, + discriminant: None, + source_info: None, + }]; + + set_members_of_composite_type(cx, self.enum_type, variant_metadata, members, None); + + let variant_info = variant_info_for(dataful_variant); + let (variant_type_metadata, member_desc_factory) = describe_enum_variant( cx, - variant, - variant_info_for(dataful_variant), + dataful_variant_layout, + variant_info, Some(NicheTag), self_metadata, self.span, ); - let variant_member_descriptions = - member_description_factory.create_member_descriptions(cx); + let member_descriptions = member_desc_factory.create_member_descriptions(cx); set_members_of_composite_type( cx, self.enum_type, variant_type_metadata, - variant_member_descriptions, + member_descriptions, Some(&self.common_members), ); - // Encode the information about the null variant in the union - // member's name. - let mut name = String::from("RUST$ENCODED$ENUM$"); - // Right now it's not even going to work for `niche_start > 0`, - // and for multiple niche variants it only supports the first. - fn compute_field_path<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - name: &mut String, - layout: TyAndLayout<'tcx>, - offset: Size, - size: Size, - ) { - for i in 0..layout.fields.count() { - let field_offset = layout.fields.offset(i); - if field_offset > offset { - continue; - } - let inner_offset = offset - field_offset; - let field = layout.field(cx, i); - if inner_offset + size <= field.size { - write!(name, "{}$", i).unwrap(); - compute_field_path(cx, name, field, inner_offset, size); - } - } - } - compute_field_path( - cx, - &mut name, - self.layout, - self.layout.fields.offset(tag_field), - self.layout.field(cx, tag_field).size, - ); - let variant_info = variant_info_for(*niche_variants.start()); - variant_info.map_struct_name(|variant_name| { - name.push_str(variant_name); - }); - - // Create the (singleton) list of descriptions of union members. - vec![MemberDescription { - name, - type_metadata: variant_type_metadata, - offset: Size::ZERO, - size: variant.size, - align: variant.align.abi, - flags: DIFlags::FlagZero, - discriminant: None, - source_info: variant_info.source_info(cx), - }] + vec![ + MemberDescription { + // Name the dataful variant so that we can identify it for natvis + name: "dataful_variant".to_string(), + type_metadata: variant_type_metadata, + offset: Size::ZERO, + size: self.layout.size, + align: self.layout.align.abi, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: variant_info.source_info(cx), + }, + MemberDescription { + name: "discriminant$".into(), + type_metadata: variant_metadata, + offset: Size::ZERO, + size: self.layout.size, + align: self.layout.align.abi, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }, + ] } else { variants .iter_enumerated() @@ -1692,19 +1759,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { Some(&self.common_members), ); - let niche_value = if i == dataful_variant { - None - } else { - let value = (i.as_u32() as u128) - .wrapping_sub(niche_variants.start().as_u32() as u128) - .wrapping_add(niche_start); - let value = tag.value.size(cx).truncate(value); - // NOTE(eddyb) do *NOT* remove this assert, until - // we pass the full 128-bit value to LLVM, otherwise - // truncation will be silent and remain undetected. - assert_eq!(value as u64 as u128, value); - Some(value as u64) - }; + let niche_value = calculate_niche_value(i); MemberDescription { name: variant_info.variant_name(), @@ -2040,9 +2095,9 @@ fn prepare_enum_metadata( if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { - Variants::Single { .. } - | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None, - Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { + Variants::Single { .. } => None, + Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. } + | Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { Some(discriminant_type_metadata(tag.value)) } }; diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 626c71abf63d..1f3e94933188 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -3,7 +3,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt}; +use rustc_target::abi::{TagEncoding, Variants}; use std::fmt::Write; @@ -46,14 +47,10 @@ pub fn push_debuginfo_type_name<'tcx>( ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), ty::Adt(def, substs) => { if def.is_enum() && cpp_like_names { - output.push_str("_enum<"); - } - - push_item_name(tcx, def.did, qualified, output); - push_type_params(tcx, substs, output, visited); - - if def.is_enum() && cpp_like_names { - output.push('>'); + msvc_enum_fallback(tcx, t, def, substs, output, visited); + } else { + push_item_name(tcx, def.did, qualified, output); + push_type_params(tcx, substs, output, visited); } } ty::Tuple(component_types) => { @@ -241,6 +238,50 @@ pub fn push_debuginfo_type_name<'tcx>( } } + fn msvc_enum_fallback( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + def: &AdtDef, + substs: SubstsRef<'tcx>, + output: &mut String, + visited: &mut FxHashSet>, + ) { + let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error"); + + if let Variants::Multiple { + tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag, + variants, + .. + } = &layout.variants + { + let dataful_variant_layout = &variants[*dataful_variant]; + + // calculate the range of values for the dataful variant + let dataful_discriminant_range = + &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range; + + let min = dataful_discriminant_range.start(); + let min = tag.value.size(&tcx).truncate(*min); + + let max = dataful_discriminant_range.end(); + let max = tag.value.size(&tcx).truncate(*max); + + output.push_str("_enum<"); + push_item_name(tcx, def.did, true, output); + push_type_params(tcx, substs, output, visited); + + let dataful_variant_name = def.variants[*dataful_variant].ident.as_str(); + + output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name)); + } else { + output.push_str("_enum<"); + push_item_name(tcx, def.did, true, output); + push_type_params(tcx, substs, output, visited); + output.push('>'); + } + } + fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) { if qualified { output.push_str(&tcx.crate_name(def_id.krate).as_str()); diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 45e36f929b4d..82d3ab15a704 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -187,4 +187,18 @@ Variant15 + + + + + + {"$T4",sb}({dataful_variant}) + {discriminant$.discriminant,en} + + dataful_variant + + {"$T4",sb} + + + From 2a9fa202fef9b1717fff3cbbe59f980c9f762c54 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 13 May 2021 12:56:33 -0400 Subject: [PATCH 17/30] Add/update tests --- src/test/debuginfo/msvc-pretty-enums.rs | 104 ++++++++++++++++++++++++ src/test/debuginfo/pretty-std.rs | 6 +- 2 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 src/test/debuginfo/msvc-pretty-enums.rs diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs new file mode 100644 index 000000000000..146be23bbb3c --- /dev/null +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -0,0 +1,104 @@ +// only-cdb +// compile-flags:-g + +// cdb-command: g + +// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb +// so the best we can do is to make sure we are generating the right debuginfo + +// cdb-command: dx -r2 a,! +// cdb-check:a,! [Type: _enum>, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: _enum>, 2, 16, Some>::Some] +// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant$ [Type: _enum>, 2, 16, Some>::discriminant$] +// cdb-check: [+0x000] discriminant : 0x2 [Type: _enum>, 2, 16, Some>::tag$] + +// cdb-command: dx -r2 b,! +// cdb-check:b,! [Type: _enum>, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: _enum>, 2, 16, Some>::Some] +// cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant$ [Type: _enum>, 2, 16, Some>::discriminant$] +// cdb-check: [+0x000] discriminant : None (0x11) [Type: _enum>, 2, 16, Some>::tag$] + +// cdb-command: dx -r2 c,! +// cdb-check:c,! [Type: _enum] +// cdb-check: [+0x000] dataful_variant [Type: _enum::Data] +// cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant$ [Type: _enum::discriminant$] +// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: _enum::tag$] + +// cdb-command: dx -r2 d,! +// cdb-check:d,! [Type: _enum] +// cdb-check: [+0x000] dataful_variant [Type: _enum::Data] +// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant$ [Type: _enum::discriminant$] +// cdb-check: [+0x000] discriminant : 0x10 [Type: _enum::tag$] + +// cdb-command: dx -r2 e,! +// cdb-check:e,! [Type: _enum] +// cdb-check: [+0x000] dataful_variant [Type: _enum::Data] +// cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant$ [Type: _enum::discriminant$] +// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: _enum::tag$] + +// cdb-command: dx -r2 f,! +// cdb-check:f,! [Type: _enum, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: _enum, 1, [...], Some>::Some] +// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] +// cdb-check: [+0x000] discriminant$ [Type: _enum, 1, [...], Some>::discriminant$] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: _enum, 1, [...], Some>::tag$] + +// cdb-command: dx -r2 g,! +// cdb-check:g,! [Type: _enum, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: _enum, 1, [...], Some>::Some] +// cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *] +// cdb-check: [+0x000] discriminant$ [Type: _enum, 1, [...], Some>::discriminant$] +// cdb-check: [+0x000] discriminant : None (0x0) [Type: _enum, 1, [...], Some>::tag$] + +// cdb-command: dx h +// cdb-check:h : Some [Type: _enum>] +// cdb-check: [+0x000] variant$ : Some (0x1) [Type: core::option::Option] +// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] + +// cdb-command: dx i +// cdb-check:i : None [Type: _enum>] +// cdb-check: [+0x000] variant$ : None (0x0) [Type: core::option::Option] + +// cdb-command: dx j +// cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] + +// cdb-command: dx -r2 k,! +// cdb-check:k,! [Type: _enum, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: _enum, 1, [...], Some>::Some] +// cdb-check: [+0x000] __0 [Type: alloc::string::String] +// cdb-check: [+0x000] discriminant$ [Type: _enum, 1, [...], Some>::discriminant$] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: _enum, 1, [...], Some>::tag$] + +pub enum CStyleEnum { + Low = 2, + High = 16, +} + +pub enum NicheLayoutEnum { + Tag1, + Data { my_data: CStyleEnum }, + Tag2, +} + +fn main() { + let a = Some(CStyleEnum::Low); + let b = Option::::None; + let c = NicheLayoutEnum::Tag1; + let d = NicheLayoutEnum::Data { my_data: CStyleEnum::High }; + let e = NicheLayoutEnum::Tag2; + let f = Some(&1u32); + let g = Option::<&'static u32>::None; + let h = Some(12u32); + let i = Option::::None; + let j = CStyleEnum::High; + let k = Some("IAMA optional string!".to_string()); + + zzz(); // #break +} + +fn zzz() { () } \ No newline at end of file diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 1a99f8412504..aad8ae5cd9fb 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -111,11 +111,11 @@ // NOTE: OsString doesn't have a .natvis entry yet. // cdb-command: dx some -// cdb-check:some : Some(8) [Type: [...]::Option] +// cdb-check:some : Some [Type: _enum>] // cdb-command: dx none -// cdb-check:none : None [Type: [...]::Option] +// cdb-check:none : None [Type: _enum>] // cdb-command: dx some_string -// cdb-check:some_string : Some("IAMA optional string!") [[...]::Option<[...]::String>] +// cdb-check:some_string [Type: _enum, 1, 18446744073709551615, Some>] #![allow(unused_variables)] use std::ffi::OsString; From d65009111734c2a4d89cad5d2fb7bbf08c813b7c Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 14 May 2021 11:17:26 -0400 Subject: [PATCH 18/30] Make tidy happy --- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 14 ++++++++++---- src/test/debuginfo/msvc-pretty-enums.rs | 3 ++- src/test/debuginfo/pretty-std.rs | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1f268bd18786..0f512fcaaaf2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1687,7 +1687,13 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { source_info: None, }]; - set_members_of_composite_type(cx, self.enum_type, variant_metadata, members, None); + set_members_of_composite_type( + cx, + self.enum_type, + variant_metadata, + members, + None, + ); let variant_info = variant_info_for(dataful_variant); let (variant_type_metadata, member_desc_factory) = describe_enum_variant( @@ -1932,9 +1938,9 @@ fn describe_enum_variant( // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); let offset = enum_layout.fields.offset(tag_field.as_usize()); - let tag_name = if cx.tcx.sess.target.is_like_msvc { "variant$" } else { "RUST$ENUM$DISR" }; - let args = - (tag_name.to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); + let tag_name = + if cx.tcx.sess.target.is_like_msvc { "variant$" } else { "RUST$ENUM$DISR" }; + let args = (tag_name.to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); (Some(offset), Some(args)) } _ => (None, None), diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index 146be23bbb3c..ad1b45a7bc27 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -1,4 +1,5 @@ // only-cdb +// ignore-tidy-linelength // compile-flags:-g // cdb-command: g @@ -101,4 +102,4 @@ fn main() { zzz(); // #break } -fn zzz() { () } \ No newline at end of file +fn zzz() { () } diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index aad8ae5cd9fb..e9f690fac2e1 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -1,6 +1,7 @@ // ignore-freebsd: gdb package too new // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155 // ignore-android: FIXME(#10381) +// ignore-tidy-linelength // compile-flags:-g // min-gdb-version: 7.7 // min-lldb-version: 310 @@ -115,7 +116,7 @@ // cdb-command: dx none // cdb-check:none : None [Type: _enum>] // cdb-command: dx some_string -// cdb-check:some_string [Type: _enum, 1, 18446744073709551615, Some>] +// cdb-check:some_string [Type: _enum, 1, [...], Some>] #![allow(unused_variables)] use std::ffi::OsString; From d2d6fa852d22eb4e9259cd708e33e7afaa9211d0 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 17 May 2021 11:09:13 -0400 Subject: [PATCH 19/30] Respond to review feedback --- .../src/debuginfo/metadata.rs | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0f512fcaaaf2..1d81d880b8de 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1534,6 +1534,19 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { .. } => { let tag_info = if fallback { + // For MSVC, we generate a union of structs for each variant with an explicit + // discriminant field roughly equivalent to the following C: + // ```c + // union _enum<{name}> { + // struct {variant 0 name} { + // tag$ variant$; + // + // } Variant0; + // + // } + // ``` + // The natvis in `intrinsic.nativs` then matches on `this.Variant0.variant$` to + // determine which variant is active and then displays it. Some(DirectTag { tag_field: Field::from(tag_field), tag_type_metadata: self.tag_type_metadata.unwrap(), @@ -1613,6 +1626,25 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { // For MSVC, we will generate a union of two structs, one for the dataful variant and one that just points to // the discriminant field. We also create an enum that contains tag values for the non-dataful variants and // make the discriminant field that type. We then use natvis to render the enum type correctly in Windbg/VS. + // This will generate debuginfo roughly equivalent to the following C: + // ```c + // union _enum<{name}, {min niche}, {max niche}, {dataful variant name} { + // struct dataful_variant { + // + // }, + // struct discriminant$ { + // enum tag$ { + // + // } discriminant; + // } + // } + // ``` + // The natvis in `intrinsic.natvis` matches on the type name `_enum<*, *, *, *>` + // and evaluates `this.discriminant$.discriminant`. If the value is between + // the min niche and max niche, then the enum is in the dataful variant and + // `this.dataful_variant` is rendered. Otherwise, the enum is in one of the + // non-dataful variants. In that case, we just need to render the name of the + // `this.discriminant$.discriminant` enum. if fallback { let unique_type_id = debug_context(cx) .type_map @@ -1938,9 +1970,7 @@ fn describe_enum_variant( // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); let offset = enum_layout.fields.offset(tag_field.as_usize()); - let tag_name = - if cx.tcx.sess.target.is_like_msvc { "variant$" } else { "RUST$ENUM$DISR" }; - let args = (tag_name.to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); + let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); (Some(offset), Some(args)) } _ => (None, None), From ef053fd6f0faa848097ff8b924ac859c667c8d15 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 20 May 2021 13:58:13 -0400 Subject: [PATCH 20/30] Change the type name from `_enum<..>` to `enum$<..>` This makes the type name inline with the proposed standard in #85269. --- .../src/debuginfo/metadata.rs | 6 +- .../src/debuginfo/type_names.rs | 4 +- src/etc/natvis/intrinsic.natvis | 4 +- src/test/debuginfo/msvc-pretty-enums.rs | 68 +++++++++---------- src/test/debuginfo/pretty-std.rs | 6 +- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1d81d880b8de..f56dace0d336 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1537,7 +1537,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { // For MSVC, we generate a union of structs for each variant with an explicit // discriminant field roughly equivalent to the following C: // ```c - // union _enum<{name}> { + // union enum$<{name}> { // struct {variant 0 name} { // tag$ variant$; // @@ -1628,7 +1628,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { // make the discriminant field that type. We then use natvis to render the enum type correctly in Windbg/VS. // This will generate debuginfo roughly equivalent to the following C: // ```c - // union _enum<{name}, {min niche}, {max niche}, {dataful variant name} { + // union enum$<{name}, {min niche}, {max niche}, {dataful variant name} { // struct dataful_variant { // // }, @@ -1639,7 +1639,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { // } // } // ``` - // The natvis in `intrinsic.natvis` matches on the type name `_enum<*, *, *, *>` + // The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>` // and evaluates `this.discriminant$.discriminant`. If the value is between // the min niche and max niche, then the enum is in the dataful variant and // `this.dataful_variant` is rendered. Otherwise, the enum is in one of the diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1f3e94933188..0f8dc06f4ca7 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -267,7 +267,7 @@ pub fn push_debuginfo_type_name<'tcx>( let max = dataful_discriminant_range.end(); let max = tag.value.size(&tcx).truncate(*max); - output.push_str("_enum<"); + output.push_str("enum$<"); push_item_name(tcx, def.did, true, output); push_type_params(tcx, substs, output, visited); @@ -275,7 +275,7 @@ pub fn push_debuginfo_type_name<'tcx>( output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name)); } else { - output.push_str("_enum<"); + output.push_str("enum$<"); push_item_name(tcx, def.did, true, output); push_type_params(tcx, substs, output, visited); output.push('>'); diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 82d3ab15a704..09b5c9f091d7 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -149,7 +149,7 @@ ... - + {tag(),en} {tag(),en} @@ -189,7 +189,7 @@ - + {"$T4",sb}({dataful_variant}) diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index ad1b45a7bc27..e2a331ca17ad 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -8,72 +8,72 @@ // so the best we can do is to make sure we are generating the right debuginfo // cdb-command: dx -r2 a,! -// cdb-check:a,! [Type: _enum>, 2, 16, Some>] -// cdb-check: [+0x000] dataful_variant [Type: _enum>, 2, 16, Some>::Some] +// cdb-check:a,! [Type: enum$>, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$>, 2, 16, Some>::Some] // cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: _enum>, 2, 16, Some>::discriminant$] -// cdb-check: [+0x000] discriminant : 0x2 [Type: _enum>, 2, 16, Some>::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$>, 2, 16, Some>::discriminant$] +// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$>, 2, 16, Some>::tag$] // cdb-command: dx -r2 b,! -// cdb-check:b,! [Type: _enum>, 2, 16, Some>] -// cdb-check: [+0x000] dataful_variant [Type: _enum>, 2, 16, Some>::Some] +// cdb-check:b,! [Type: enum$>, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$>, 2, 16, Some>::Some] // cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: _enum>, 2, 16, Some>::discriminant$] -// cdb-check: [+0x000] discriminant : None (0x11) [Type: _enum>, 2, 16, Some>::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$>, 2, 16, Some>::discriminant$] +// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$>, 2, 16, Some>::tag$] // cdb-command: dx -r2 c,! -// cdb-check:c,! [Type: _enum] -// cdb-check: [+0x000] dataful_variant [Type: _enum::Data] +// cdb-check:c,! [Type: enum$] +// cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: _enum::discriminant$] -// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: _enum::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$::discriminant$] +// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$::tag$] // cdb-command: dx -r2 d,! -// cdb-check:d,! [Type: _enum] -// cdb-check: [+0x000] dataful_variant [Type: _enum::Data] +// cdb-check:d,! [Type: enum$] +// cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: _enum::discriminant$] -// cdb-check: [+0x000] discriminant : 0x10 [Type: _enum::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$::discriminant$] +// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$::tag$] // cdb-command: dx -r2 e,! -// cdb-check:e,! [Type: _enum] -// cdb-check: [+0x000] dataful_variant [Type: _enum::Data] +// cdb-check:e,! [Type: enum$] +// cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: _enum::discriminant$] -// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: _enum::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$::discriminant$] +// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$::tag$] // cdb-command: dx -r2 f,! -// cdb-check:f,! [Type: _enum, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: _enum, 1, [...], Some>::Some] +// cdb-check:f,! [Type: enum$, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant$ [Type: _enum, 1, [...], Some>::discriminant$] -// cdb-check: [+0x000] discriminant : 0x[...] [Type: _enum, 1, [...], Some>::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$, 1, [...], Some>::discriminant$] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::tag$] // cdb-command: dx -r2 g,! -// cdb-check:g,! [Type: _enum, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: _enum, 1, [...], Some>::Some] +// cdb-check:g,! [Type: enum$, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant$ [Type: _enum, 1, [...], Some>::discriminant$] -// cdb-check: [+0x000] discriminant : None (0x0) [Type: _enum, 1, [...], Some>::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$, 1, [...], Some>::discriminant$] +// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$, 1, [...], Some>::tag$] // cdb-command: dx h -// cdb-check:h : Some [Type: _enum>] +// cdb-check:h : Some [Type: enum$>] // cdb-check: [+0x000] variant$ : Some (0x1) [Type: core::option::Option] // cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] // cdb-command: dx i -// cdb-check:i : None [Type: _enum>] +// cdb-check:i : None [Type: enum$>] // cdb-check: [+0x000] variant$ : None (0x0) [Type: core::option::Option] // cdb-command: dx j // cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] // cdb-command: dx -r2 k,! -// cdb-check:k,! [Type: _enum, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: _enum, 1, [...], Some>::Some] +// cdb-check:k,! [Type: enum$, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 [Type: alloc::string::String] -// cdb-check: [+0x000] discriminant$ [Type: _enum, 1, [...], Some>::discriminant$] -// cdb-check: [+0x000] discriminant : 0x[...] [Type: _enum, 1, [...], Some>::tag$] +// cdb-check: [+0x000] discriminant$ [Type: enum$, 1, [...], Some>::discriminant$] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::tag$] pub enum CStyleEnum { Low = 2, diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index e9f690fac2e1..68e73b5f38da 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -112,11 +112,11 @@ // NOTE: OsString doesn't have a .natvis entry yet. // cdb-command: dx some -// cdb-check:some : Some [Type: _enum>] +// cdb-check:some : Some [Type: enum$>] // cdb-command: dx none -// cdb-check:none : None [Type: _enum>] +// cdb-check:none : None [Type: enum$>] // cdb-command: dx some_string -// cdb-check:some_string [Type: _enum, 1, [...], Some>] +// cdb-check:some_string [Type: enum$, 1, [...], Some>] #![allow(unused_variables)] use std::ffi::OsString; From 3127419e2b2cb4ad2e44a06d30af6a015daf4557 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 26 May 2021 12:02:07 -0400 Subject: [PATCH 21/30] Respond to review feedback --- .../src/debuginfo/metadata.rs | 90 ++++++------------- .../src/debuginfo/type_names.rs | 4 + src/etc/natvis/intrinsic.natvis | 41 ++++----- src/test/debuginfo/msvc-pretty-enums.rs | 24 ++--- 4 files changed, 61 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index f56dace0d336..1e70664e64d7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1485,8 +1485,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { _ => bug!(), }; - // This will always find the metadata in the type map. let fallback = use_enum_fallback(cx); + // This will always find the metadata in the type map. let self_metadata = type_metadata(cx, self.enum_type, self.span); match self.layout.variants { @@ -1541,11 +1541,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { // struct {variant 0 name} { // tag$ variant$; // - // } Variant0; + // } variant0; // // } // ``` - // The natvis in `intrinsic.nativs` then matches on `this.Variant0.variant$` to + // The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to // determine which variant is active and then displays it. Some(DirectTag { tag_field: Field::from(tag_field), @@ -1582,7 +1582,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { MemberDescription { name: if fallback { - format!("Variant{}", i.as_u32()) + format!("variant{}", i.as_u32()) } else { variant_info.variant_name() }, @@ -1623,43 +1623,27 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } }; - // For MSVC, we will generate a union of two structs, one for the dataful variant and one that just points to - // the discriminant field. We also create an enum that contains tag values for the non-dataful variants and - // make the discriminant field that type. We then use natvis to render the enum type correctly in Windbg/VS. + // For MSVC, we will generate a union of two fields, one for the dataful variant + // and one that just points to the discriminant. We also create an enum that + // contains tag values for the non-dataful variants and make the discriminant field + // that type. We then use natvis to render the enum type correctly in Windbg/VS. // This will generate debuginfo roughly equivalent to the following C: // ```c - // union enum$<{name}, {min niche}, {max niche}, {dataful variant name} { - // struct dataful_variant { + // union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> { + // struct { // - // }, - // struct discriminant$ { - // enum tag$ { - // - // } discriminant; - // } + // } dataful_variant; + // enum Discriminant$ { + // + // } discriminant; // } // ``` // The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>` - // and evaluates `this.discriminant$.discriminant`. If the value is between - // the min niche and max niche, then the enum is in the dataful variant and - // `this.dataful_variant` is rendered. Otherwise, the enum is in one of the - // non-dataful variants. In that case, we just need to render the name of the - // `this.discriminant$.discriminant` enum. + // and evaluates `this.discriminant`. If the value is between the min niche and max + // niche, then the enum is in the dataful variant and `this.dataful_variant` is + // rendered. Otherwise, the enum is in one of the non-dataful variants. In that + // case, we just need to render the name of the `this.discriminant` enum. if fallback { - let unique_type_id = debug_context(cx) - .type_map - .borrow_mut() - .get_unique_type_id_of_enum_variant(cx, self.enum_type, "discriminant$"); - - let variant_metadata = create_struct_stub( - cx, - self.layout.ty, - &"discriminant$", - unique_type_id, - Some(self_metadata), - DIFlags::FlagArtificial, - ); - let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant); let mut discr_enum_ty = tag.value.to_ty(cx.tcx); @@ -1694,8 +1678,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), self_metadata, - "tag$".as_ptr().cast(), - "tag$".len(), + "Discriminant$".as_ptr().cast(), + "Discriminant$".len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, tag.value.size(cx).bits(), @@ -1706,27 +1690,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { ) }; - let (size, align) = - cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty); - let members = vec![MemberDescription { - name: "discriminant".to_string(), - type_metadata: discr_enum, - offset: dataful_variant_layout.fields.offset(tag_field), - size, - align, - flags: DIFlags::FlagArtificial, - discriminant: None, - source_info: None, - }]; - - set_members_of_composite_type( - cx, - self.enum_type, - variant_metadata, - members, - None, - ); - let variant_info = variant_info_for(dataful_variant); let (variant_type_metadata, member_desc_factory) = describe_enum_variant( cx, @@ -1747,6 +1710,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { Some(&self.common_members), ); + let (size, align) = + cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty); + vec![ MemberDescription { // Name the dataful variant so that we can identify it for natvis @@ -1760,11 +1726,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { source_info: variant_info.source_info(cx), }, MemberDescription { - name: "discriminant$".into(), - type_metadata: variant_metadata, - offset: Size::ZERO, - size: self.layout.size, - align: self.layout.align.abi, + name: "discriminant".into(), + type_metadata: discr_enum, + offset: dataful_variant_layout.fields.offset(tag_field), + size, + align, flags: DIFlags::FlagZero, discriminant: None, source_info: None, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 0f8dc06f4ca7..7b4b0821c4be 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -238,6 +238,10 @@ pub fn push_debuginfo_type_name<'tcx>( } } + /// MSVC names enums differently than other platforms so that the debugging visualization + // format (natvis) is able to understand enums and render the active variant correctly in the + // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and + // `EnumMemberDescriptionFactor::create_member_descriptions`. fn msvc_enum_fallback( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 09b5c9f091d7..89280149a035 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -150,7 +150,7 @@ - + {tag(),en} {tag(),en} {tag(),en} @@ -169,31 +169,32 @@ {tag(),en} - Variant0 - Variant1 - Variant2 - Variant3 - Variant4 - Variant5 - Variant6 - Variant7 - Variant8 - Variant9 - Variant10 - Variant11 - Variant12 - Variant13 - Variant14 - Variant15 + variant0 + variant1 + variant2 + variant3 + variant4 + variant5 + variant6 + variant7 + variant8 + variant9 + variant10 + variant11 + variant12 + variant13 + variant14 + variant15 - + - + {"$T4",sb}({dataful_variant}) - {discriminant$.discriminant,en} + {discriminant,en} dataful_variant diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index e2a331ca17ad..550cc66f3899 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -11,50 +11,43 @@ // cdb-check:a,! [Type: enum$>, 2, 16, Some>] // cdb-check: [+0x000] dataful_variant [Type: enum$>, 2, 16, Some>::Some] // cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: enum$>, 2, 16, Some>::discriminant$] -// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$>, 2, 16, Some>::tag$] +// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$>, 2, 16, Some>::Discriminant$] // cdb-command: dx -r2 b,! // cdb-check:b,! [Type: enum$>, 2, 16, Some>] // cdb-check: [+0x000] dataful_variant [Type: enum$>, 2, 16, Some>::Some] // cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: enum$>, 2, 16, Some>::discriminant$] -// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$>, 2, 16, Some>::tag$] +// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$>, 2, 16, Some>::Discriminant$] // cdb-command: dx -r2 c,! // cdb-check:c,! [Type: enum$] // cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: enum$::discriminant$] -// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$::tag$] +// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$::Discriminant$] // cdb-command: dx -r2 d,! // cdb-check:d,! [Type: enum$] // cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: enum$::discriminant$] -// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$::tag$] +// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$::Discriminant$] // cdb-command: dx -r2 e,! // cdb-check:e,! [Type: enum$] // cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant$ [Type: enum$::discriminant$] -// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$::tag$] +// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$::Discriminant$] // cdb-command: dx -r2 f,! // cdb-check:f,! [Type: enum$, 1, [...], Some>] // cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant$ [Type: enum$, 1, [...], Some>::discriminant$] -// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::tag$] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::Discriminant$] // cdb-command: dx -r2 g,! // cdb-check:g,! [Type: enum$, 1, [...], Some>] // cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant$ [Type: enum$, 1, [...], Some>::discriminant$] -// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$, 1, [...], Some>::tag$] +// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$, 1, [...], Some>::Discriminant$] // cdb-command: dx h // cdb-check:h : Some [Type: enum$>] @@ -72,8 +65,7 @@ // cdb-check:k,! [Type: enum$, 1, [...], Some>] // cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 [Type: alloc::string::String] -// cdb-check: [+0x000] discriminant$ [Type: enum$, 1, [...], Some>::discriminant$] -// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::tag$] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::Discriminant$] pub enum CStyleEnum { Low = 2, From 012c32346748f7781ff2143e9f4e53d64f2527d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 2 Jun 2021 00:00:00 +0000 Subject: [PATCH 22/30] Implement `Ty::is_enum` using `matches!` --- compiler/rustc_middle/src/ty/sty.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f35ecb4d3cd5..1222ed7b4d69 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1837,10 +1837,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_enum(&self) -> bool { - match self.kind() { - Adt(adt_def, _) => adt_def.is_enum(), - _ => false, - } + matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum()) } #[inline] From c898681a8683fb5622ec77e1d7ecb641e1cd0328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 2 Jun 2021 00:00:00 +0000 Subject: [PATCH 23/30] Add `Ty::is_union` predicate and use it --- compiler/rustc_middle/src/ty/sty.rs | 5 +++++ compiler/rustc_mir/src/borrow_check/mod.rs | 12 +++++------- .../src/borrow_check/places_conflict.rs | 19 ++++++++----------- .../src/dataflow/move_paths/builder.rs | 6 ++---- .../src/transform/check_consts/validation.rs | 8 ++------ .../rustc_mir/src/transform/check_unsafety.rs | 2 +- compiler/rustc_mir/src/transform/dest_prop.rs | 15 +++------------ .../rustc_mir/src/transform/promote_consts.rs | 6 ++---- .../rustc_mir/src/transform/remove_zsts.rs | 11 ++--------- compiler/rustc_typeck/src/check/place_op.rs | 2 +- 10 files changed, 31 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 1222ed7b4d69..012d9bd82c81 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1840,6 +1840,11 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum()) } + #[inline] + pub fn is_union(&self) -> bool { + matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union()) + } + #[inline] pub fn is_closure(&self) -> bool { matches!(self.kind(), Closure(..)) diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 4c35be39a3d3..36eb8a4baa83 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -1965,13 +1965,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() { - if def.is_union() { - if this.move_data.path_map[mpi].iter().any(|moi| { - this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) - }) { - return; - } + if base.ty(this.body(), tcx).ty.is_union() { + if this.move_data.path_map[mpi].iter().any(|moi| { + this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) + }) { + return; } } diff --git a/compiler/rustc_mir/src/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs index 3654b51949e7..d21550a8e1af 100644 --- a/compiler/rustc_mir/src/borrow_check/places_conflict.rs +++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs @@ -331,17 +331,14 @@ fn place_projection_conflict<'tcx>( Overlap::EqualOrDisjoint } else { let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; - match ty.kind() { - ty::Adt(def, _) if def.is_union() => { - // Different fields of a union, we are basically stuck. - debug!("place_element_conflict: STUCK-UNION"); - Overlap::Arbitrary - } - _ => { - // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } + if ty.is_union() { + // Different fields of a union, we are basically stuck. + debug!("place_element_conflict: STUCK-UNION"); + Overlap::Arbitrary + } else { + // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! + debug!("place_element_conflict: DISJOINT-FIELD"); + Overlap::Disjoint } } } diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index 1bfbb843114d..cea465ea1ed9 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -519,10 +519,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // Check if we are assigning into a field of a union, if so, lookup the place // of the union so it is marked as initialized again. if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() { - if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() { - if def.is_union() { - place = place_base; - } + if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() { + place = place_base; } } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 41d9d0d04b50..bff02efc49df 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -753,12 +753,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; - match base_ty.ty_adt_def() { - Some(def) if def.is_union() => { - self.check_op(ops::UnionAccess); - } - - _ => {} + if base_ty.is_union() { + self.check_op(ops::UnionAccess); } } } diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index 955be8cc81e1..8d4316c30b3e 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } let base_ty = base.ty(self.body, self.tcx).ty; - if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) { + if base_ty.is_union() { // If we did not hit a `Deref` yet and the overall place use is an assignment, the // rules are different. let assign_to_field = !saw_deref diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 29df86ca6cdb..4f5a467a6ee6 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -114,7 +114,7 @@ use rustc_middle::mir::{ traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::TyCtxt; // Empirical measurements have resulted in some observations: // - Running on a body with a single block and 500 locals takes barely any time @@ -910,17 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { // Handle the "subtle case" described above by rejecting any `dest` that is or // projects through a union. - let is_union = |ty: Ty<'_>| { - if let ty::Adt(def, _) = ty.kind() { - if def.is_union() { - return true; - } - } - - false - }; let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return; } for elem in dest.projection { @@ -930,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { } place_ty = place_ty.projection_ty(self.tcx, elem); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return; } } diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index f6b1323e1079..78e84419c62c 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -415,11 +415,9 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::Field(..) => { let base_ty = place_base.ty(self.body, self.tcx).ty; - if let Some(def) = base_ty.ty_adt_def() { + if base_ty.is_union() { // No promotion of union field accesses. - if def.is_union() { - return Err(Unpromotable); - } + return Err(Unpromotable); } } } diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs index 70f7538dd57a..a0f225e6de60 100644 --- a/compiler/rustc_mir/src/transform/remove_zsts.rs +++ b/compiler/rustc_mir/src/transform/remove_zsts.rs @@ -69,21 +69,14 @@ fn involves_a_union<'tcx>( tcx: TyCtxt<'tcx>, ) -> bool { let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return true; } for elem in place.projection { place_ty = place_ty.projection_ty(tcx, elem); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return true; } } return false; } - -fn is_union(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Adt(def, _) if def.is_union() => true, - _ => false, - } -} diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index a63aec07ad1c..652b82f1063c 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -248,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Clear previous flag; after a pointer indirection it does not apply any more. inside_union = false; } - if source.ty_adt_def().map_or(false, |adt| adt.is_union()) { + if source.is_union() { inside_union = true; } // Fix up the autoderefs. Autorefs can only occur immediately preceding From 957e2effc3287a1342ecc54cbf8e04ae21a3f6af Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Wed, 2 Jun 2021 23:10:55 +0800 Subject: [PATCH 24/30] Address comment --- compiler/rustc_passes/src/stability.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index c6c165544a94..29a0a3c48e53 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -828,10 +828,9 @@ impl Visitor<'tcx> for Checker<'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) { if let Some(def_id) = path.res.opt_def_id() { - let method_span = if path.segments.len() >= 2 { - path.segments.last().map(|s| s.ident.span) - } else { - None + let method_span = match path.segments { + [.., _, last] => Some(last.ident.span), + _ => None, }; self.tcx.check_stability(def_id, Some(id), path.span, method_span) } From 11478bd614641eccf8987ea3d489070bba85c2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 2 Jun 2021 00:00:00 +0000 Subject: [PATCH 25/30] Validate type of locals used as indices --- compiler/rustc_mir/src/transform/validate.rs | 22 ++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index d009b0b1b238..835789069bb2 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -11,8 +11,9 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::traversal; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ - AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef, - Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, + AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem, + PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator, + TerminatorKind, }; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable}; @@ -217,6 +218,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.super_operand(operand, location); } + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let ProjectionElem::Index(index) = elem { + let index_ty = self.body.local_decls[index].ty; + if index_ty != self.tcx.types.usize { + self.fail(location, format!("bad index ({:?} != usize)", index_ty)) + } + } + self.super_projection_elem(local, proj_base, elem, context, location); + } + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match &statement.kind { StatementKind::Assign(box (dest, rvalue)) => { From f7c283c160c7fb0c0f5ff9202fb66564e228daef Mon Sep 17 00:00:00 2001 From: SOFe Date: Mon, 22 Mar 2021 10:46:18 +0800 Subject: [PATCH 26/30] Stabilize `vecdeque_binary_search` --- library/alloc/src/collections/vec_deque/mod.rs | 10 +++------- library/alloc/tests/lib.rs | 1 - 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 7d6fbf1c438b..28178bc6cb7d 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2416,7 +2416,6 @@ impl VecDeque { /// found; the fourth could match any position in `[1, 4]`. /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); @@ -2432,7 +2431,6 @@ impl VecDeque { /// sort order: /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); @@ -2441,7 +2439,7 @@ impl VecDeque { /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.52.0")] #[inline] pub fn binary_search(&self, x: &T) -> Result where @@ -2476,7 +2474,6 @@ impl VecDeque { /// found; the fourth could match any position in `[1, 4]`. /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); @@ -2487,7 +2484,7 @@ impl VecDeque { /// let r = deque.binary_search_by(|x| x.cmp(&1)); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.52.0")] pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result where F: FnMut(&'a T) -> Ordering, @@ -2530,7 +2527,6 @@ impl VecDeque { /// fourth could match any position in `[1, 4]`. /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1), @@ -2543,7 +2539,7 @@ impl VecDeque { /// let r = deque.binary_search_by_key(&1, |&(a, b)| b); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.52.0")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result where diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 25a83a0b0143..3143afa269dd 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -17,7 +17,6 @@ #![feature(binary_heap_as_slice)] #![feature(inplace_iteration)] #![feature(iter_map_while)] -#![feature(vecdeque_binary_search)] #![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(vec_spare_capacity)] From f51f277d6c008d56cc9bb0576bf5ebca60070208 Mon Sep 17 00:00:00 2001 From: SOFe Date: Mon, 22 Mar 2021 10:58:06 +0800 Subject: [PATCH 27/30] Bumped `vecdeque_binary_search` stabilization version to 1.53.0 --- library/alloc/src/collections/vec_deque/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 28178bc6cb7d..910c42699136 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2439,7 +2439,7 @@ impl VecDeque { /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` - #[stable(feature = "vecdeque_binary_search", since = "1.52.0")] + #[stable(feature = "vecdeque_binary_search", since = "1.53.0")] #[inline] pub fn binary_search(&self, x: &T) -> Result where @@ -2484,7 +2484,7 @@ impl VecDeque { /// let r = deque.binary_search_by(|x| x.cmp(&1)); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[stable(feature = "vecdeque_binary_search", since = "1.52.0")] + #[stable(feature = "vecdeque_binary_search", since = "1.53.0")] pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result where F: FnMut(&'a T) -> Ordering, @@ -2539,7 +2539,7 @@ impl VecDeque { /// let r = deque.binary_search_by_key(&1, |&(a, b)| b); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[stable(feature = "vecdeque_binary_search", since = "1.52.0")] + #[stable(feature = "vecdeque_binary_search", since = "1.53.0")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result where From f086f1ec903e1b21ba0ca207c828ceb48f590079 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 2 Jun 2021 20:51:08 +0200 Subject: [PATCH 28/30] Bump vecdeque_binary_search stabilization to 1.54. --- library/alloc/src/collections/vec_deque/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 910c42699136..c04597b822aa 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2439,7 +2439,7 @@ impl VecDeque { /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` - #[stable(feature = "vecdeque_binary_search", since = "1.53.0")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] #[inline] pub fn binary_search(&self, x: &T) -> Result where @@ -2484,7 +2484,7 @@ impl VecDeque { /// let r = deque.binary_search_by(|x| x.cmp(&1)); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[stable(feature = "vecdeque_binary_search", since = "1.53.0")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result where F: FnMut(&'a T) -> Ordering, @@ -2539,7 +2539,7 @@ impl VecDeque { /// let r = deque.binary_search_by_key(&1, |&(a, b)| b); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[stable(feature = "vecdeque_binary_search", since = "1.53.0")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result where From f717992229841e802770ed163c2d6e2a54cc577f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 2 Jun 2021 20:51:23 +0200 Subject: [PATCH 29/30] Stabilize VecDeque::partition_point. --- library/alloc/src/collections/vec_deque/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index c04597b822aa..5d03be35e466 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2570,7 +2570,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into(); @@ -2580,7 +2579,7 @@ impl VecDeque { /// assert!(deque.iter().take(i).all(|&x| x < 5)); /// assert!(deque.iter().skip(i).all(|&x| !(x < 5))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] pub fn partition_point

(&self, mut pred: P) -> usize where P: FnMut(&T) -> bool, From 94c45ef1089bfd9fa4304cf67dedce4788883051 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 2 Jun 2021 16:09:23 -0400 Subject: [PATCH 30/30] Update generator tests --- src/test/codegen/async-fn-debug-msvc.rs | 16 ++++++++-------- src/test/codegen/generator-debug-msvc.rs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index f2641404aae2..e410180bfff6 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -17,33 +17,33 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]] -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0" +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 12, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 14, // CHECK-SAME: baseType: [[VARIANT:![0-9]*]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]], +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]], // CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 44be71f3b9b8..7edb07d224c3 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -21,33 +21,33 @@ fn generator_test() -> impl Generator { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]] -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0" +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 18, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 18, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 17, // CHECK-SAME: baseType: [[VARIANT:![0-9]*]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]], +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]], // CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial