From f85b0c456f763a70a8eae0e4a9daf6a4005ef87a Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 24 Feb 2020 18:06:42 +0900 Subject: [PATCH 01/21] Remove use of `unwrap()` from save-analysis --- src/librustc_save_analysis/lib.rs | 19 +++++++++++-------- src/test/ui/assign-to-method.rs | 2 ++ src/test/ui/assign-to-method.stderr | 4 ++-- src/test/ui/issues/issue-3763.rs | 2 ++ src/test/ui/issues/issue-3763.stderr | 10 +++++----- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b253559dd5cd5..a46be2dcd82d5 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -533,14 +533,17 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { match self.tables.expr_ty_adjusted(&hir_node).kind { ty::Adt(def, _) if !def.is_enum() => { let variant = &def.non_enum_variant(); - let index = self.tcx.find_field_index(ident, variant).unwrap(); - filter!(self.span_utils, ident.span); - let span = self.span_from_span(ident.span); - return Some(Data::RefData(Ref { - kind: RefKind::Variable, - span, - ref_id: id_from_def_id(variant.fields[index].did), - })); + if let Some(index) = self.tcx.find_field_index(ident, variant) { + filter!(self.span_utils, ident.span); + let span = self.span_from_span(ident.span); + return Some(Data::RefData(Ref { + kind: RefKind::Variable, + span, + ref_id: id_from_def_id(variant.fields[index].did), + })); + } + + None } ty::Tuple(..) => None, _ => { diff --git a/src/test/ui/assign-to-method.rs b/src/test/ui/assign-to-method.rs index 95f066c382c8d..dec096252253a 100644 --- a/src/test/ui/assign-to-method.rs +++ b/src/test/ui/assign-to-method.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zsave-analysis + struct Cat { meows : usize, diff --git a/src/test/ui/assign-to-method.stderr b/src/test/ui/assign-to-method.stderr index feceadb67220b..b9ef49acd6da2 100644 --- a/src/test/ui/assign-to-method.stderr +++ b/src/test/ui/assign-to-method.stderr @@ -1,5 +1,5 @@ error[E0615]: attempted to take value of method `speak` on type `Cat` - --> $DIR/assign-to-method.rs:20:8 + --> $DIR/assign-to-method.rs:22:8 | LL | nyan.speak = || println!("meow"); | ^^^^^ @@ -7,7 +7,7 @@ LL | nyan.speak = || println!("meow"); = help: methods are immutable and cannot be assigned to error[E0615]: attempted to take value of method `speak` on type `Cat` - --> $DIR/assign-to-method.rs:21:8 + --> $DIR/assign-to-method.rs:23:8 | LL | nyan.speak += || println!("meow"); | ^^^^^ diff --git a/src/test/ui/issues/issue-3763.rs b/src/test/ui/issues/issue-3763.rs index 5d17a30ab3624..a220151c41631 100644 --- a/src/test/ui/issues/issue-3763.rs +++ b/src/test/ui/issues/issue-3763.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zsave-analysis + mod my_mod { pub struct MyStruct { priv_field: isize diff --git a/src/test/ui/issues/issue-3763.stderr b/src/test/ui/issues/issue-3763.stderr index 50169286b1ceb..3db962142b5b2 100644 --- a/src/test/ui/issues/issue-3763.stderr +++ b/src/test/ui/issues/issue-3763.stderr @@ -1,29 +1,29 @@ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:15:19 + --> $DIR/issue-3763.rs:17:19 | LL | let _woohoo = (&my_struct).priv_field; | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:18:19 + --> $DIR/issue-3763.rs:20:19 | LL | let _woohoo = (Box::new(my_struct)).priv_field; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0624]: method `happyfun` is private - --> $DIR/issue-3763.rs:21:18 + --> $DIR/issue-3763.rs:23:18 | LL | (&my_struct).happyfun(); | ^^^^^^^^ error[E0624]: method `happyfun` is private - --> $DIR/issue-3763.rs:23:27 + --> $DIR/issue-3763.rs:25:27 | LL | (Box::new(my_struct)).happyfun(); | ^^^^^^^^ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:24:16 + --> $DIR/issue-3763.rs:26:16 | LL | let nope = my_struct.priv_field; | ^^^^^^^^^^^^^^^^^^^^ From a211a82b3c7e450edd99ff6d3cf77a0cedae0d2e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 24 Feb 2020 23:22:46 +0900 Subject: [PATCH 02/21] Address review comment --- src/librustc_save_analysis/lib.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index a46be2dcd82d5..22df31cc526d6 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -533,17 +533,17 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { match self.tables.expr_ty_adjusted(&hir_node).kind { ty::Adt(def, _) if !def.is_enum() => { let variant = &def.non_enum_variant(); - if let Some(index) = self.tcx.find_field_index(ident, variant) { - filter!(self.span_utils, ident.span); - let span = self.span_from_span(ident.span); - return Some(Data::RefData(Ref { - kind: RefKind::Variable, - span, - ref_id: id_from_def_id(variant.fields[index].did), - })); - } - - None + filter!(self.span_utils, ident.span); + let span = self.span_from_span(ident.span); + return Some(Data::RefData(Ref { + kind: RefKind::Variable, + span, + ref_id: self + .tcx + .find_field_index(ident, variant) + .map(|index| id_from_def_id(variant.fields[index].did)) + .unwrap_or_else(|| null_id()), + })); } ty::Tuple(..) => None, _ => { From 5307edce6faa5c675dc57a1dd3b4fdcbf1ebdc7d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 25 Feb 2020 00:21:45 +0900 Subject: [PATCH 03/21] Tweak tests --- src/test/ui/assign-to-method.rs | 24 ------------------- src/test/ui/issues/issue-3763.rs | 1 + src/test/ui/issues/issue-3763.stderr | 10 ++++---- src/test/ui/methods/assign-to-method.rs | 24 +++++++++++++++++++ .../ui/{ => methods}/assign-to-method.stderr | 12 +++++----- 5 files changed, 36 insertions(+), 35 deletions(-) delete mode 100644 src/test/ui/assign-to-method.rs create mode 100644 src/test/ui/methods/assign-to-method.rs rename src/test/ui/{ => methods}/assign-to-method.stderr (65%) diff --git a/src/test/ui/assign-to-method.rs b/src/test/ui/assign-to-method.rs deleted file mode 100644 index dec096252253a..0000000000000 --- a/src/test/ui/assign-to-method.rs +++ /dev/null @@ -1,24 +0,0 @@ -// compile-flags: -Zsave-analysis - -struct Cat { - meows : usize, - - how_hungry : isize, -} - -impl Cat { - pub fn speak(&self) { self.meows += 1; } -} - -fn cat(in_x : usize, in_y : isize) -> Cat { - Cat { - meows: in_x, - how_hungry: in_y - } -} - -fn main() { - let nyan : Cat = cat(52, 99); - nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method - nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method -} diff --git a/src/test/ui/issues/issue-3763.rs b/src/test/ui/issues/issue-3763.rs index a220151c41631..3494df37fe7f1 100644 --- a/src/test/ui/issues/issue-3763.rs +++ b/src/test/ui/issues/issue-3763.rs @@ -1,4 +1,5 @@ // compile-flags: -Zsave-analysis +// Also regression test for #69416 mod my_mod { pub struct MyStruct { diff --git a/src/test/ui/issues/issue-3763.stderr b/src/test/ui/issues/issue-3763.stderr index 3db962142b5b2..873f69d390e67 100644 --- a/src/test/ui/issues/issue-3763.stderr +++ b/src/test/ui/issues/issue-3763.stderr @@ -1,29 +1,29 @@ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:17:19 + --> $DIR/issue-3763.rs:18:19 | LL | let _woohoo = (&my_struct).priv_field; | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:20:19 + --> $DIR/issue-3763.rs:21:19 | LL | let _woohoo = (Box::new(my_struct)).priv_field; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0624]: method `happyfun` is private - --> $DIR/issue-3763.rs:23:18 + --> $DIR/issue-3763.rs:24:18 | LL | (&my_struct).happyfun(); | ^^^^^^^^ error[E0624]: method `happyfun` is private - --> $DIR/issue-3763.rs:25:27 + --> $DIR/issue-3763.rs:26:27 | LL | (Box::new(my_struct)).happyfun(); | ^^^^^^^^ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:26:16 + --> $DIR/issue-3763.rs:27:16 | LL | let nope = my_struct.priv_field; | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/methods/assign-to-method.rs b/src/test/ui/methods/assign-to-method.rs new file mode 100644 index 0000000000000..85beaee8df0a1 --- /dev/null +++ b/src/test/ui/methods/assign-to-method.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zsave-analysis +// Also regression test for #69409 + +struct Cat { + meows : usize, + how_hungry : isize, +} + +impl Cat { + pub fn speak(&self) { self.meows += 1; } +} + +fn cat(in_x : usize, in_y : isize) -> Cat { + Cat { + meows: in_x, + how_hungry: in_y + } +} + +fn main() { + let nyan : Cat = cat(52, 99); + nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method + nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method +} diff --git a/src/test/ui/assign-to-method.stderr b/src/test/ui/methods/assign-to-method.stderr similarity index 65% rename from src/test/ui/assign-to-method.stderr rename to src/test/ui/methods/assign-to-method.stderr index b9ef49acd6da2..c0dd529b6818f 100644 --- a/src/test/ui/assign-to-method.stderr +++ b/src/test/ui/methods/assign-to-method.stderr @@ -1,16 +1,16 @@ error[E0615]: attempted to take value of method `speak` on type `Cat` - --> $DIR/assign-to-method.rs:22:8 + --> $DIR/assign-to-method.rs:22:10 | -LL | nyan.speak = || println!("meow"); - | ^^^^^ +LL | nyan.speak = || println!("meow"); + | ^^^^^ | = help: methods are immutable and cannot be assigned to error[E0615]: attempted to take value of method `speak` on type `Cat` - --> $DIR/assign-to-method.rs:23:8 + --> $DIR/assign-to-method.rs:23:10 | -LL | nyan.speak += || println!("meow"); - | ^^^^^ +LL | nyan.speak += || println!("meow"); + | ^^^^^ | = help: methods are immutable and cannot be assigned to From f9db3c243bae6c0618f83a36520b3fa7e726d693 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 29 Feb 2020 03:22:18 +0900 Subject: [PATCH 04/21] Clean up unstable book --- .../language-features/const-in-array-repeat-expressions.md | 2 +- .../src/language-features/impl-trait-in-bindings.md | 4 ++-- src/doc/unstable-book/src/language-features/link-cfg.md | 5 +++++ src/doc/unstable-book/src/language-features/trait-alias.md | 2 +- .../src/language-features/transparent-unions.md | 2 +- .../unstable-book/src/library-features/read-initializer.md | 7 ------- .../library-features/tidy-test-never-used-anywhere-else.md | 5 +++++ 7 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/link-cfg.md delete mode 100644 src/doc/unstable-book/src/library-features/read-initializer.md create mode 100644 src/doc/unstable-book/src/library-features/tidy-test-never-used-anywhere-else.md diff --git a/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md b/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md index 09d1b19b4c3c3..940916944bdaa 100644 --- a/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md +++ b/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md @@ -2,7 +2,7 @@ The tracking issue for this feature is: [#49147] -[#44109]: https://github.com/rust-lang/rust/issues/49147 +[#49147]: https://github.com/rust-lang/rust/issues/49147 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md b/src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md index 896465cf64978..5c6aa912c1b24 100644 --- a/src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md +++ b/src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md @@ -1,8 +1,8 @@ # `impl_trait_in_bindings` -The tracking issue for this feature is: [#34511] +The tracking issue for this feature is: [#63065] -[#34511]: https://github.com/rust-lang/rust/issues/34511 +[#63065]: https://github.com/rust-lang/rust/issues/63065 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/link-cfg.md b/src/doc/unstable-book/src/language-features/link-cfg.md new file mode 100644 index 0000000000000..ee0fd5bf8698c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/link-cfg.md @@ -0,0 +1,5 @@ +# `link_cfg` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/language-features/trait-alias.md b/src/doc/unstable-book/src/language-features/trait-alias.md index 4f2db040160c3..f1be053ddc42e 100644 --- a/src/doc/unstable-book/src/language-features/trait-alias.md +++ b/src/doc/unstable-book/src/language-features/trait-alias.md @@ -2,7 +2,7 @@ The tracking issue for this feature is: [#41517] -[#41417]: https://github.com/rust-lang/rust/issues/41517 +[#41517]: https://github.com/rust-lang/rust/issues/41517 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/transparent-unions.md b/src/doc/unstable-book/src/language-features/transparent-unions.md index b731c9ea6d012..9b39b8971644f 100644 --- a/src/doc/unstable-book/src/language-features/transparent-unions.md +++ b/src/doc/unstable-book/src/language-features/transparent-unions.md @@ -2,7 +2,7 @@ The tracking issue for this feature is [#60405] -[60405]: https://github.com/rust-lang/rust/issues/60405 +[#60405]: https://github.com/rust-lang/rust/issues/60405 ---- diff --git a/src/doc/unstable-book/src/library-features/read-initializer.md b/src/doc/unstable-book/src/library-features/read-initializer.md deleted file mode 100644 index 898fe58eeee53..0000000000000 --- a/src/doc/unstable-book/src/library-features/read-initializer.md +++ /dev/null @@ -1,7 +0,0 @@ -# `read_initializer` - -The tracking issue for this feature is: [#42788] - -[#0]: https://github.com/rust-lang/rust/issues/42788 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/tidy-test-never-used-anywhere-else.md b/src/doc/unstable-book/src/library-features/tidy-test-never-used-anywhere-else.md new file mode 100644 index 0000000000000..c194d79a19d3e --- /dev/null +++ b/src/doc/unstable-book/src/library-features/tidy-test-never-used-anywhere-else.md @@ -0,0 +1,5 @@ +# `tidy_test_never_used_anywhere_else` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ From 4c9e87e989bd15bde318e4a03836591658826445 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 29 Feb 2020 23:29:46 +0900 Subject: [PATCH 05/21] Stop generating `compiler_builtins_lib` doc --- src/tools/tidy/src/features.rs | 14 -------------- src/tools/tidy/src/unstable_book.rs | 18 ++---------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 12f93a87cb172..d9320e9147cff 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -63,20 +63,6 @@ pub struct CollectedFeatures { pub fn collect_lib_features(base_src_path: &Path) -> Features { let mut lib_features = Features::new(); - // This library feature is defined in the `compiler_builtins` crate, which - // has been moved out-of-tree. Now it can no longer be auto-discovered by - // `tidy`, because we need to filter out its (submodule) directory. Manually - // add it to the set of known library features so we can still generate docs. - lib_features.insert( - "compiler_builtins_lib".to_owned(), - Feature { - level: Status::Unstable, - since: None, - has_gate_test: false, - tracking_issue: None, - }, - ); - map_lib_features(base_src_path, &mut |res, _, _| { if let Ok((name, feature)) = res { lib_features.insert(name.to_owned(), feature); diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index 472d66459d724..7dfb6224d240a 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -1,4 +1,4 @@ -use crate::features::{CollectedFeatures, Feature, Features, Status}; +use crate::features::{CollectedFeatures, Features, Status}; use std::collections::BTreeSet; use std::fs; use std::path::{Path, PathBuf}; @@ -73,26 +73,12 @@ fn collect_unstable_book_lib_features_section_file_names(base_src_path: &Path) - pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) { let lang_features = features.lang; - let mut lib_features = features + let lib_features = features .lib .into_iter() .filter(|&(ref name, _)| !lang_features.contains_key(name)) .collect::(); - // This library feature is defined in the `compiler_builtins` crate, which - // has been moved out-of-tree. Now it can no longer be auto-discovered by - // `tidy`, because we need to filter out its (submodule) directory. Manually - // add it to the set of known library features so we can still generate docs. - lib_features.insert( - "compiler_builtins_lib".to_owned(), - Feature { - level: Status::Unstable, - since: None, - has_gate_test: false, - tracking_issue: None, - }, - ); - // Library features let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features); let unstable_book_lib_features_section_file_names = From c55df3786a944e10615075184a507554cf7d7c39 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 1 Mar 2020 00:35:49 +0900 Subject: [PATCH 06/21] Make `rustc_attrs` tracking issue None --- src/librustc_feature/active.rs | 6 +++--- .../min_const_fn/allow_const_fn_ptr_feature_gate.stderr | 1 - src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr | 3 --- src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr | 4 ---- .../on-unimplemented/feature-gate-on-unimplemented.stderr | 1 - src/test/ui/proc-macro/expand-to-unstable-2.stderr | 1 - src/test/ui/reserved/reserved-attr-on-macro.stderr | 1 - src/test/ui/suggestions/attribute-typos.stderr | 1 - src/test/ui/tool-attributes/diagnostic_item.stderr | 1 - 9 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 0082f4f1a6e89..380dfc4a0673f 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -99,6 +99,9 @@ declare_features! ( // no-tracking-issue-start + /// Allows using `rustc_*` attributes (RFC 572). + (active, rustc_attrs, "1.0.0", None, None), + /// Allows using compiler's own crates. (active, rustc_private, "1.0.0", Some(27812), None), @@ -128,9 +131,6 @@ declare_features! ( /// Allows using `#[link_name="llvm.*"]`. (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - /// Allows using `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", Some(29642), None), - /// Allows using the `box $expr` syntax. (active, box_syntax, "1.0.0", Some(49733), None), diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr index c8d060f5cdcfe..7794cc7583dfc 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr @@ -4,7 +4,6 @@ error[E0658]: internal implementation detail LL | #[rustc_allow_const_fn_ptr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 082d897c01dc1..82dec1fd4cf21 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -4,7 +4,6 @@ error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit test LL | #[rustc_variance] | ^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable @@ -13,7 +12,6 @@ error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests a LL | #[rustc_error] | ^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable @@ -22,7 +20,6 @@ error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just u LL | #[rustc_nonnull_optimization_guaranteed] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr index 58f8b4e703513..1e039f17a0d11 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc::unknown] | ^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: expected attribute, found macro `rustc::unknown` @@ -19,7 +18,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[unknown::rustc] | ^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: expected attribute, found macro `unknown::rustc` @@ -34,7 +32,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc_unknown] | ^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: cannot find attribute `rustc_unknown` in this scope @@ -49,7 +46,6 @@ error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests a LL | #[rustc_dummy] | ^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to 7 previous errors diff --git a/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr b/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr index 71baf92b2d409..a4b33963fb0b9 100644 --- a/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr +++ b/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr @@ -4,7 +4,6 @@ error[E0658]: this is an internal attribute that will never be stable LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.stderr b/src/test/ui/proc-macro/expand-to-unstable-2.stderr index ff2e3af3777a1..19144b210a127 100644 --- a/src/test/ui/proc-macro/expand-to-unstable-2.stderr +++ b/src/test/ui/proc-macro/expand-to-unstable-2.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[derive(Unstable)] | ^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr index 2870cb57e9caf..c387bba0a1310 100644 --- a/src/test/ui/reserved/reserved-attr-on-macro.stderr +++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc_attribute_should_be_reserved] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: cannot determine resolution for the macro `foo` diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr index 10a119a628c70..c7c257ba5fe53 100644 --- a/src/test/ui/suggestions/attribute-typos.stderr +++ b/src/test/ui/suggestions/attribute-typos.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc_err] | ^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: cannot find attribute `rustc_err` in this scope diff --git a/src/test/ui/tool-attributes/diagnostic_item.stderr b/src/test/ui/tool-attributes/diagnostic_item.stderr index d12834084e714..743e4b658c6b7 100644 --- a/src/test/ui/tool-attributes/diagnostic_item.stderr +++ b/src/test/ui/tool-attributes/diagnostic_item.stderr @@ -4,7 +4,6 @@ error[E0658]: diagnostic items compiler internal support for linting LL | #[rustc_diagnostic_item = "foomp"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to previous error From 2746e12948ee4d152f8d8acfb5873f970effe501 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 1 Mar 2020 03:52:45 +0100 Subject: [PATCH 07/21] check_binding_alt_eq_ty: improve precision wrt. `if let`. --- src/librustc_typeck/check/pat.rs | 12 ++++++++++-- .../or-patterns-binding-type-mismatch.stderr | 16 ++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index d5cc19f986f45..2a8be6a02445f 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -559,8 +559,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let var_ty = self.resolve_vars_with_obligations(var_ty); let msg = format!("first introduced with type `{}` here", var_ty); err.span_label(hir.span(var_id), msg); - let in_arm = hir.parent_iter(var_id).any(|(_, n)| matches!(n, hir::Node::Arm(..))); - let pre = if in_arm { "in the same arm, " } else { "" }; + let in_match = hir.parent_iter(var_id).any(|(_, n)| { + matches!( + n, + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Match(.., hir::MatchSource::Normal), + .. + }) + ) + }); + let pre = if in_match { "in the same arm, " } else { "" }; err.note(&format!("{}a binding must have the same type in all alternatives", pre)); err.emit(); } diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr index d5e029d668d47..1dabb7c975430 100644 --- a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr +++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr @@ -101,7 +101,7 @@ LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { | | expected `usize`, found `isize` | first introduced with type `usize` here | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:38:47 @@ -112,7 +112,7 @@ LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) | | expected `usize`, found `isize` | first introduced with type `usize` here | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:42:22 @@ -123,7 +123,7 @@ LL | if let (x, y) | (y, x) = (0u8, 1u16) { | | expected `u16`, found `u8` | first introduced with type `u16` here | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:42:25 @@ -134,7 +134,7 @@ LL | if let (x, y) | (y, x) = (0u8, 1u16) { | | expected `u8`, found `u16` | first introduced with type `u8` here | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:44 @@ -147,7 +147,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:53 @@ -160,7 +160,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:62 @@ -173,7 +173,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:65 @@ -184,7 +184,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` | - = note: in the same arm, a binding must have the same type in all alternatives + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:55:39 From 8ea676eccaa3596c56b5bf665a1adb155b634ff3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 2 Mar 2020 10:00:05 -0800 Subject: [PATCH 08/21] Update books --- src/doc/embedded-book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/embedded-book b/src/doc/embedded-book index b2e1092bf67bd..b81ffb7a6f4c5 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit b2e1092bf67bd4d7686c4553f186edbb7f5f92db +Subproject commit b81ffb7a6f4c5aaed92786e770e99db116aa4ebd diff --git a/src/doc/nomicon b/src/doc/nomicon index 3e6e1001dc6e0..9f797e65e6bcc 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 3e6e1001dc6e095dbd5c88005e80969f60e384e1 +Subproject commit 9f797e65e6bcc79419975b17aff8e21c9adc039f diff --git a/src/doc/reference b/src/doc/reference index 64239df6d1735..559e09caa9661 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 64239df6d173562b9deb4f012e4c3e6e960c4754 +Subproject commit 559e09caa9661043744cf7af7bd88432d966f743 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 32facd5522ddb..db57f899ea2a5 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 32facd5522ddbbf37baf01e4e4b6562bc55c071a +Subproject commit db57f899ea2a56a544c8d280cbf033438666273d From 44c97c43b5d3df5d76381f80fb8ad0042c6ccf55 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Fri, 6 Mar 2020 14:32:54 +0100 Subject: [PATCH 09/21] Fix & test leak of some BTreeMap nodes on panic during `into_iter` --- src/liballoc/collections/btree/map.rs | 11 ++++++++++- src/liballoc/tests/btree/map.rs | 26 +++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 8b9ffdfb49b46..9da324ba2d4f1 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1477,6 +1477,14 @@ impl Drop for IntoIter { // Continue the same loop we perform below. This only runs when unwinding, so we // don't have to care about panics this time (they'll abort). while let Some(_) = self.0.next() {} + + // No need to avoid the shared root, because the tree was definitely not empty. + unsafe { + let mut node = ptr::read(&self.0.front).into_node().forget_type(); + while let Some(parent) = node.deallocate_and_ascend() { + node = parent.into_node().forget_type(); + } + } } } @@ -1491,7 +1499,8 @@ impl Drop for IntoIter { if node.is_shared_root() { return; } - + // Most of the nodes have been deallocated while traversing + // but one pile from a leaf up to the root is left standing. while let Some(parent) = node.deallocate_and_ascend() { node = parent.into_node().forget_type(); } diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index fd07a4d3926c3..d05eec19346de 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -1021,7 +1021,7 @@ fn test_split_off_large_random_sorted() { } #[test] -fn test_into_iter_drop_leak() { +fn test_into_iter_drop_leak_1() { static DROPS: AtomicU32 = AtomicU32::new(0); struct D; @@ -1045,3 +1045,27 @@ fn test_into_iter_drop_leak() { assert_eq!(DROPS.load(Ordering::SeqCst), 5); } + +#[test] +fn test_into_iter_drop_leak_2() { + let size = 12; // to obtain tree with 2 levels (having edges to leaf nodes) + static DROPS: AtomicU32 = AtomicU32::new(0); + static PANIC_POINT: AtomicU32 = AtomicU32::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == PANIC_POINT.load(Ordering::SeqCst) { + panic!("panic in `drop`"); + } + } + } + + for panic_point in vec![0, 1, size - 2, size - 1] { + DROPS.store(0, Ordering::SeqCst); + PANIC_POINT.store(panic_point, Ordering::SeqCst); + let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect(); + catch_unwind(move || drop(map.into_iter())).ok(); + assert_eq!(DROPS.load(Ordering::SeqCst), size); + } +} From 6548be2ba95c29cfd0f3324f4b314a64853b2f57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 11:45:02 +0100 Subject: [PATCH 10/21] 'fieldless enums' is not what I meant -- it's empty/uninhabited enums, really --- src/librustc_mir/interpret/validity.rs | 3 +-- src/librustc_target/abi/mod.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 731dcc6a25f14..8989da9a91a8a 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -579,13 +579,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } // Check primitive types. We do this after checking for uninhabited types, - // to exclude fieldless enums (that also appear as fieldless unions here). + // to exclude uninhabited enums (that also appear as fieldless unions here). // Primitives can have varying layout, so we check them separately and before aggregate // handling. // It is CRITICAL that we get this check right, or we might be validating the wrong thing! let primitive = match op.layout.fields { // Primitives appear as Union with 0 fields - except for Boxes and fat pointers. - // (Fieldless enums also appear here, but they are uninhabited and thus handled above.) layout::FieldPlacement::Union(0) => true, _ => op.layout.ty.builtin_deref(true).is_some(), }; diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index ffef38cedfc17..316e07425c528 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -872,7 +872,7 @@ impl Niche { #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct LayoutDetails { /// Says where the fields are located within the layout. - /// Primitives and fieldless enums appear as unions without fields. + /// Primitives and uninhabited enums appear as unions without fields. pub fields: FieldPlacement, /// Encodes information about multi-variant layouts. From d47196b2ec23a26c03b1546449f29300d42a4840 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 13:09:13 +0100 Subject: [PATCH 11/21] miri value visitor: detect primitives by type, not layout --- src/librustc_mir/interpret/validity.rs | 284 ++++++++++-------- .../ui/consts/const-eval/ub-uninhabit.stderr | 2 +- .../validate_uninhabited_zsts.stderr | 2 +- .../ui/consts/validate_never_arrays.stderr | 6 +- 4 files changed, 163 insertions(+), 131 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 8989da9a91a8a..defb490199b30 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -306,23 +306,119 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M Ok(()) } - fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + /// Check a reference or `Box`. + fn check_safe_pointer(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { let value = self.ecx.read_immediate(value)?; + // Handle wide pointers. + // Check metadata early, for better diagnostics + let place = try_validation!(self.ecx.ref_to_mplace(value), "undefined pointer", self.path); + if place.layout.is_unsized() { + self.check_wide_ptr_meta(place.meta, place.layout)?; + } + // Make sure this is dereferenceable and all. + let (size, align) = self + .ecx + .size_and_align_of(place.meta, place.layout)? + // for the purpose of validity, consider foreign types to have + // alignment and size determined by the layout (size will be 0, + // alignment should take attributes into account). + .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); + let ptr: Option<_> = match self.ecx.memory.check_ptr_access_align( + place.ptr, + size, + Some(align), + CheckInAllocMsg::InboundsTest, + ) { + Ok(ptr) => ptr, + Err(err) => { + info!( + "{:?} did not pass access check for size {:?}, align {:?}", + place.ptr, size, align + ); + match err.kind { + err_unsup!(InvalidNullPointerUsage) => { + throw_validation_failure!("a NULL reference", self.path) + } + err_unsup!(AlignmentCheckFailed { required, has }) => { + throw_validation_failure!( + format_args!( + "an unaligned reference \ + (required {} byte alignment but found {})", + required.bytes(), + has.bytes() + ), + self.path + ) + } + err_unsup!(ReadBytesAsPointer) => throw_validation_failure!( + "a dangling reference (created from integer)", + self.path + ), + _ => throw_validation_failure!( + "a dangling reference (not entirely in bounds)", + self.path + ), + } + } + }; + // Recursive checking + if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts { + if let Some(ptr) = ptr { + // not a ZST + // Skip validation entirely for some external statics + let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id); + if let Some(GlobalAlloc::Static(did)) = alloc_kind { + // `extern static` cannot be validated as they have no body. + // FIXME: Statics from other crates are also skipped. + // They might be checked at a different type, but for now we + // want to avoid recursing too deeply. This is not sound! + if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { + return Ok(()); + } + } + } + // Proceed recursively even for ZST, no reason to skip them! + // `!` is a ZST and we want to validate it. + // Normalize before handing `place` to tracking because that will + // check for duplicates. + let place = if size.bytes() > 0 { + self.ecx.force_mplace_ptr(place).expect("we already bounds-checked") + } else { + place + }; + let path = &self.path; + ref_tracking.track(place, || { + // We need to clone the path anyway, make sure it gets created + // with enough space for the additional `Deref`. + let mut new_path = Vec::with_capacity(path.len() + 1); + new_path.clone_from(path); + new_path.push(PathElem::Deref); + new_path + }); + } + Ok(()) + } + + /// Check if this is a value of primitive type, and if yes check the validity of the value + /// at that type. Return `true` if the type is indeed primitive. + fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; match ty.kind { ty::Bool => { - let value = value.to_scalar_or_undef(); + let value = self.ecx.read_scalar(value)?; try_validation!(value.to_bool(), value, self.path, "a boolean"); + Ok(true) } ty::Char => { - let value = value.to_scalar_or_undef(); + let value = self.ecx.read_scalar(value)?; try_validation!(value.to_char(), value, self.path, "a valid unicode codepoint"); + Ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { + let value = self.ecx.read_scalar(value)?; // NOTE: Keep this in sync with the array optimization for int/float // types below! - let value = value.to_scalar_or_undef(); if self.ref_tracking_for_consts.is_some() { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous let is_bits = value.not_undef().map_or(false, |v| v.is_bits()); @@ -337,108 +433,32 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M // At run-time, for now, we accept *anything* for these types, including // undef. We should fix that, but let's start low. } + Ok(true) } ty::RawPtr(..) => { // We are conservative with undef for integers, but try to // actually enforce our current rules for raw pointers. - let place = - try_validation!(self.ecx.ref_to_mplace(value), "undefined pointer", self.path); + let place = try_validation!( + self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), + "undefined pointer", + self.path + ); if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; } + Ok(true) } - _ if ty.is_box() || ty.is_region_ptr() => { - // Handle wide pointers. - // Check metadata early, for better diagnostics - let place = - try_validation!(self.ecx.ref_to_mplace(value), "undefined pointer", self.path); - if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta, place.layout)?; - } - // Make sure this is dereferenceable and all. - let (size, align) = self - .ecx - .size_and_align_of(place.meta, place.layout)? - // for the purpose of validity, consider foreign types to have - // alignment and size determined by the layout (size will be 0, - // alignment should take attributes into account). - .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); - let ptr: Option<_> = match self.ecx.memory.check_ptr_access_align( - place.ptr, - size, - Some(align), - CheckInAllocMsg::InboundsTest, - ) { - Ok(ptr) => ptr, - Err(err) => { - info!( - "{:?} did not pass access check for size {:?}, align {:?}", - place.ptr, size, align - ); - match err.kind { - err_unsup!(InvalidNullPointerUsage) => { - throw_validation_failure!("a NULL reference", self.path) - } - err_unsup!(AlignmentCheckFailed { required, has }) => { - throw_validation_failure!( - format_args!( - "an unaligned reference \ - (required {} byte alignment but found {})", - required.bytes(), - has.bytes() - ), - self.path - ) - } - err_unsup!(ReadBytesAsPointer) => throw_validation_failure!( - "a dangling reference (created from integer)", - self.path - ), - _ => throw_validation_failure!( - "a dangling reference (not entirely in bounds)", - self.path - ), - } - } - }; - // Recursive checking - if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts { - if let Some(ptr) = ptr { - // not a ZST - // Skip validation entirely for some external statics - let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id); - if let Some(GlobalAlloc::Static(did)) = alloc_kind { - // `extern static` cannot be validated as they have no body. - // FIXME: Statics from other crates are also skipped. - // They might be checked at a different type, but for now we - // want to avoid recursing too deeply. This is not sound! - if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { - return Ok(()); - } - } - } - // Proceed recursively even for ZST, no reason to skip them! - // `!` is a ZST and we want to validate it. - // Normalize before handing `place` to tracking because that will - // check for duplicates. - let place = if size.bytes() > 0 { - self.ecx.force_mplace_ptr(place).expect("we already bounds-checked") - } else { - place - }; - let path = &self.path; - ref_tracking.track(place, || { - // We need to clone the path anyway, make sure it gets created - // with enough space for the additional `Deref`. - let mut new_path = Vec::with_capacity(path.len() + 1); - new_path.clone_from(path); - new_path.push(PathElem::Deref); - new_path - }); - } + ty::Ref(..) => { + self.check_safe_pointer(value)?; + Ok(true) + } + ty::Adt(def, ..) if def.is_box() => { + // FIXME make sure we have a test for `Box`! + self.check_safe_pointer(value)?; + Ok(true) } ty::FnPtr(_sig) => { - let value = value.to_scalar_or_undef(); + let value = self.ecx.read_scalar(value)?; let _fn = try_validation!( value.not_undef().and_then(|ptr| self.ecx.memory.get_fn(ptr)), value, @@ -446,11 +466,35 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M "a function pointer" ); // FIXME: Check if the signature matches + Ok(true) } - // This should be all the (inhabited) primitive types - _ => bug!("Unexpected primitive type {}", value.layout.ty), + ty::Never => throw_validation_failure!("a value of the never type `!`", self.path), + ty::Foreign(..) | ty::FnDef(..) => { + // Nothing to check. + Ok(true) + } + // This should be all the (inhabited) primitive types. The rest is compound, we + // check them by visiting their fields/variants. + // (`Str` UTF-8 check happens in `visit_aggregate`, too.) + ty::Adt(..) + | ty::Tuple(..) + | ty::Array(..) + | ty::Slice(..) + | ty::Str + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) => Ok(false), + // Some types only occur during inference, we should not see them here. + ty::Error + | ty::Infer(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Param(..) + | ty::Opaque(..) + | ty::UnnormalizedProjection(..) + | ty::Projection(..) => bug!("Encountered invalid type {:?}", ty), } - Ok(()) } fn visit_scalar( @@ -558,11 +602,10 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } #[inline(always)] - fn visit_union(&mut self, _v: Self::V, fields: usize) -> InterpResult<'tcx> { - // Empty unions are not accepted by rustc. That's great, it means we can - // use that as a signal for detecting primitives. Make sure - // we did not miss any primitive. - assert!(fields > 0); + fn visit_union(&mut self, op: OpTy<'tcx, M::PointerTag>, fields: usize) -> InterpResult<'tcx> { + // Empty unions are not accepted by rustc. But uninhabited enums + // claim to be unions, so allow them, too. + assert!(op.layout.abi.is_uninhabited() || fields > 0); Ok(()) } @@ -570,28 +613,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { trace!("visit_value: {:?}, {:?}", *op, op.layout); - if op.layout.abi.is_uninhabited() { - // Uninhabited types do not have sensible layout, stop right here. - throw_validation_failure!( - format_args!("a value of uninhabited type {:?}", op.layout.ty), - self.path - ) - } - - // Check primitive types. We do this after checking for uninhabited types, - // to exclude uninhabited enums (that also appear as fieldless unions here). - // Primitives can have varying layout, so we check them separately and before aggregate - // handling. - // It is CRITICAL that we get this check right, or we might be validating the wrong thing! - let primitive = match op.layout.fields { - // Primitives appear as Union with 0 fields - except for Boxes and fat pointers. - layout::FieldPlacement::Union(0) => true, - _ => op.layout.ty.builtin_deref(true).is_some(), - }; - if primitive { - // No need to recurse further or check scalar layout, this is a leaf type. - return self.visit_primitive(op); + // Check primitive types -- the leafs of our recursive descend. + if self.visit_primitive(op)? { + return Ok(()); } + // Sanity check: `builtin_deref` does not know any pointers that are not primitive. + assert!(op.layout.ty.builtin_deref(true).is_none()); // Recursively walk the type. Translate some possible errors to something nicer. match self.walk_value(op) { @@ -618,7 +645,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // scalars, we do the same check on every "level" (e.g., first we check // MyNewtype and then the scalar in there). match op.layout.abi { - layout::Abi::Uninhabited => unreachable!(), // checked above + layout::Abi::Uninhabited => { + throw_validation_failure!( + format_args!("a value of uninhabited type {:?}", op.layout.ty), + self.path + ); + } layout::Abi::Scalar(ref scalar_layout) => { self.visit_scalar(op, scalar_layout)?; } diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.stderr index 4fef9aa84ea19..350d8353fef19 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.stderr @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:21:1 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type [Bar; 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr index 2a338e276402c..d0e35615dab42 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -20,7 +20,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_uninhabited_zsts.rs:17:1 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type [Empty; 3] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/validate_never_arrays.stderr b/src/test/ui/consts/validate_never_arrays.stderr index 203620a771b8f..77f0a2ebd4021 100644 --- a/src/test/ui/consts/validate_never_arrays.stderr +++ b/src/test/ui/consts/validate_never_arrays.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:3:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type [!; 1] at . + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .[0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -10,7 +10,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:6:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type ! at .[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .[0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:7:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type ! at .[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .[0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. From aa1435b0aef77e0eeb8604fd0eed578772ff7e27 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 20:37:33 +0100 Subject: [PATCH 12/21] const validation ub tests: use transmute instead of unions --- src/test/ui/consts/const-eval/ub-enum.rs | 49 +++---- src/test/ui/consts/const-eval/ub-enum.stderr | 52 +++---- src/test/ui/consts/const-eval/ub-nonnull.rs | 6 +- .../ui/consts/const-eval/ub-nonnull.stderr | 4 +- src/test/ui/consts/const-eval/ub-uninhabit.rs | 10 +- .../ui/consts/const-eval/ub-uninhabit.stderr | 8 +- src/test/ui/consts/const-eval/ub-wide-ptr.rs | 129 ++++++------------ .../ui/consts/const-eval/ub-wide-ptr.stderr | 128 +++++++++-------- 8 files changed, 165 insertions(+), 221 deletions(-) diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 483285aa4e123..4e7c7be4a76ed 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -1,5 +1,7 @@ +#![feature(const_transmute)] #![allow(const_err)] // make sure we cannot allow away the errors tested here +use std::mem; #[repr(transparent)] #[derive(Copy, Clone)] @@ -10,23 +12,16 @@ struct Wrap(T); enum Enum { A = 0, } -#[repr(C)] -union TransmuteEnum { - in1: &'static u8, - in2: usize, - out1: Enum, - out2: Wrap, -} -const GOOD_ENUM: Enum = unsafe { TransmuteEnum { in2: 0 }.out1 }; +const GOOD_ENUM: Enum = unsafe { mem::transmute(0usize) }; -const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; +const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; //~^ ERROR is undefined behavior -const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; +const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; //~^ ERROR is undefined behavior -const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; +const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; //~^ ERROR is undefined behavior // (Potentially) invalid enum discriminant @@ -36,39 +31,31 @@ enum Enum2 { A = 2, } -#[repr(C)] -union TransmuteEnum2 { - in1: usize, - in2: &'static u8, - in3: (), - out1: Enum2, - out2: Wrap, // something wrapping the enum so that we test layout first, not enum - out3: Option, -} -const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; +const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; //~^ ERROR is undefined behavior -const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; +const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; //~^ ERROR is undefined behavior -const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; +// something wrapping the enum so that we test layout first, not enum +const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; //~^ ERROR is undefined behavior // Undef enum discriminant. -const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; +#[repr(C)] +union MaybeUninit { + uninit: (), + init: T, +} +const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR is undefined behavior // Pointer value in an enum with a niche that is not just 0. -const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; +const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; //~^ ERROR is undefined behavior // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). -#[repr(C)] -union TransmuteChar { - a: u32, - b: char, -} // Need to create something which does not clash with enum layout optimizations. -const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); +const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); //~^ ERROR is undefined behavior fn main() { diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 8c47d68e9686b..95d4155be91f2 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -1,72 +1,72 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:23:1 + --> $DIR/ub-enum.rs:18:1 | -LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant +LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:26:1 + --> $DIR/ub-enum.rs:21:1 | -LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes +LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:29:1 + --> $DIR/ub-enum.rs:24:1 | -LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes +LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:48:1 + --> $DIR/ub-enum.rs:34:1 | -LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant +LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:50:1 + --> $DIR/ub-enum.rs:36:1 | -LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes +LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:52:1 + --> $DIR/ub-enum.rs:39:1 | -LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes +LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:56:1 + --> $DIR/ub-enum.rs:48:1 | -LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; +LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:60:1 + --> $DIR/ub-enum.rs:52:1 | -LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes +LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:71:1 + --> $DIR/ub-enum.rs:58:1 | -LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected a valid unicode codepoint +LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected a valid unicode codepoint | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-nonnull.rs b/src/test/ui/consts/const-eval/ub-nonnull.rs index 8ce64ced7dff4..1f46b6c98ad2f 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.rs +++ b/src/test/ui/consts/const-eval/ub-nonnull.rs @@ -25,11 +25,11 @@ const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value #[repr(C)] -union Transmute { +union MaybeUninit { uninit: (), - out: NonZeroU8, + init: T, } -const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; +const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR it is undefined behavior to use this value // Also test other uses of rustc_layout_scalar_valid_range_start diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index ec0561870576f..edfc7ac837fc7 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -43,8 +43,8 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:32:1 | -LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes +LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.rs b/src/test/ui/consts/const-eval/ub-uninhabit.rs index d2745d71bdb2f..e7350ae271673 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.rs +++ b/src/test/ui/consts/const-eval/ub-uninhabit.rs @@ -7,18 +7,18 @@ use std::mem; enum Bar {} #[repr(C)] -union TransmuteUnion { - a: A, - b: B, +union MaybeUninit { + uninit: (), + init: T, } -const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b }; +const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR it is undefined behavior to use this value const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; //~^ ERROR it is undefined behavior to use this value -const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b }; +const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR it is undefined behavior to use this value fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.stderr index 350d8353fef19..8ce4279a8b7dd 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,8 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:15:1 | -LL | const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar +LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -17,8 +17,8 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:21:1 | -LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0] +LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index a5c2a57c6c886..ada82fc83a8c7 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -1,72 +1,18 @@ // ignore-tidy-linelength +#![feature(const_transmute)] #![allow(unused)] #![allow(const_err)] // make sure we cannot allow away the errors tested here +use std::mem; + // normalize-stderr-test "offset \d+" -> "offset N" // normalize-stderr-test "allocation \d+" -> "allocation N" // normalize-stderr-test "size \d+" -> "size N" #[repr(C)] -union BoolTransmute { - val: u8, - bl: bool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct SliceRepr { - ptr: *const u8, - len: usize, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadSliceRepr { - ptr: *const u8, - len: &'static u8, -} - -#[repr(C)] -union SliceTransmute { - repr: SliceRepr, - bad: BadSliceRepr, - addr: usize, - slice: &'static [u8], - raw_slice: *const [u8], - str: &'static str, - my_str: &'static MyStr, - my_slice: &'static MySliceBool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr { - ptr: *const u8, - vtable: *const u8, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr2 { - ptr: *const u8, - vtable: *const u64, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadDynRepr { - ptr: *const u8, - vtable: usize, -} - -#[repr(C)] -union DynTransmute { - repr: DynRepr, - repr2: DynRepr2, - bad: BadDynRepr, - addr: usize, - rust: &'static dyn Trait, - raw_rust: *const dyn Trait, +union MaybeUninit { + uninit: (), + init: T, } trait Trait {} @@ -81,90 +27,93 @@ type MySliceBool = MySlice<[bool]>; // # str // OK -const STR_VALID: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str}; +const STR_VALID: &str = unsafe { mem::transmute((&42u8, 1usize)) }; // bad str -const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; +const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; //~^ ERROR it is undefined behavior to use this value // bad str -const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; +const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value // bad str in user-defined unsized type -const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; +const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value // invalid UTF-8 -const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; +const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; //~^ ERROR it is undefined behavior to use this value // invalid UTF-8 in user-defined str-like -const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; +const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; //~^ ERROR it is undefined behavior to use this value // # slice // OK -const SLICE_VALID: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice}; +const SLICE_VALID: &[u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // bad slice: length uninit -const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; +const SLICE_LENGTH_UNINIT: &[u8] = unsafe { //~^ ERROR it is undefined behavior to use this value + let uninit_len = MaybeUninit:: { uninit: () }; + mem::transmute((42, uninit_len)) +}; // bad slice: length too big -const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; +const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; //~^ ERROR it is undefined behavior to use this value // bad slice: length not an int -const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; +const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value // bad data *inside* the slice -const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; +const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; //~^ ERROR it is undefined behavior to use this value // good MySliceBool const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]); // bad: sized field is not okay -const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); +const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); //~^ ERROR it is undefined behavior to use this value // bad: unsized part is not okay -const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); +const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); //~^ ERROR it is undefined behavior to use this value // # raw slice -const RAW_SLICE_VALID: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.raw_slice}; // ok -const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.raw_slice}; // ok because raw -const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: usize::max_value() } }.raw_slice}; // ok because raw -const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; +const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // ok +const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw +const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::max_value())) }; // ok because raw +const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { //~^ ERROR it is undefined behavior to use this value + let uninit_len = MaybeUninit:: { uninit: () }; + mem::transmute((42, uninit_len)) +}; // # trait object // bad trait object -const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; +const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; //~^ ERROR it is undefined behavior to use this value // bad trait object -const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; +const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; //~^ ERROR it is undefined behavior to use this value // bad trait object -const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; +const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; //~^ ERROR it is undefined behavior to use this value // bad data *inside* the trait object -const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; +const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; //~^ ERROR it is undefined behavior to use this value // # raw trait object -const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust}; +const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; //~^ ERROR it is undefined behavior to use this value -const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; +const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; //~^ ERROR it is undefined behavior to use this value -const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl } as *const _; // ok because raw +const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw // Const eval fails for these, so they need to be statics to error. static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { - DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust + mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) //~^ ERROR could not evaluate static initializer }; static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { - DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust + mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) //~^ ERROR could not evaluate static initializer }; -fn main() { - let _ = RAW_TRAIT_OBJ_VTABLE_NULL; - let _ = RAW_TRAIT_OBJ_VTABLE_INVALID; -} +fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr index 4da9ad6c3327c..2a3ae7dfe6de5 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -1,158 +1,166 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:86:1 + --> $DIR/ub-wide-ptr.rs:32:1 | -LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (not entirely in bounds) +LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (not entirely in bounds) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:89:1 + --> $DIR/ub-wide-ptr.rs:35:1 | -LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer +LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:92:1 + --> $DIR/ub-wide-ptr.rs:38:1 | -LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer +LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:96:1 + --> $DIR/ub-wide-ptr.rs:42:1 | -LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . +LL | const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:99:1 + --> $DIR/ub-wide-ptr.rs:45:1 | -LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 +LL | const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:106:1 + --> $DIR/ub-wide-ptr.rs:52:1 | -LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer +LL | / const SLICE_LENGTH_UNINIT: &[u8] = unsafe { +LL | | +LL | | let uninit_len = MaybeUninit:: { uninit: () }; +LL | | mem::transmute((42, uninit_len)) +LL | | }; + | |__^ type validation failed: encountered undefined pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:109:1 + --> $DIR/ub-wide-ptr.rs:58:1 | -LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (not entirely in bounds) +LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (not entirely in bounds) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:112:1 + --> $DIR/ub-wide-ptr.rs:61:1 | -LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer +LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:116:1 + --> $DIR/ub-wide-ptr.rs:65:1 | -LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected a boolean +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:122:1 + --> $DIR/ub-wide-ptr.rs:71:1 | -LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected a boolean +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 + --> $DIR/ub-wide-ptr.rs:74:1 | -LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected a boolean +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:132:1 + --> $DIR/ub-wide-ptr.rs:81:1 | -LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer +LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { +LL | | +LL | | let uninit_len = MaybeUninit:: { uninit: () }; +LL | | mem::transmute((42, uninit_len)) +LL | | }; + | |__^ type validation failed: encountered undefined pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:137:1 + --> $DIR/ub-wide-ptr.rs:89:1 | -LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:140:1 + --> $DIR/ub-wide-ptr.rs:92:1 | -LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:143:1 + --> $DIR/ub-wide-ptr.rs:95:1 | -LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:147:1 + --> $DIR/ub-wide-ptr.rs:99:1 | -LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected a boolean +LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:151:1 + --> $DIR/ub-wide-ptr.rs:103:1 | -LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:153:1 + --> $DIR/ub-wide-ptr.rs:105:1 | -LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:159:5 + --> $DIR/ub-wide-ptr.rs:111:5 | -LL | DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer +LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:163:5 + --> $DIR/ub-wide-ptr.rs:115:5 | -LL | DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N +LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N error: aborting due to 20 previous errors From 4807e939cdeba02b0752ba5748eec9ef4e9f1af8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 20:52:27 +0100 Subject: [PATCH 13/21] test that we validate boxes --- src/librustc_mir/interpret/validity.rs | 1 - src/test/ui/consts/const-eval/ub-ref.rs | 13 +++++++ src/test/ui/consts/const-eval/ub-ref.stderr | 40 ++++++++++++++++++--- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index defb490199b30..ee4d05c5911de 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -453,7 +453,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M Ok(true) } ty::Adt(def, ..) if def.is_box() => { - // FIXME make sure we have a test for `Box`! self.check_safe_pointer(value)?; Ok(true) } diff --git a/src/test/ui/consts/const-eval/ub-ref.rs b/src/test/ui/consts/const-eval/ub-ref.rs index 889579ca1ecef..14ededafaff04 100644 --- a/src/test/ui/consts/const-eval/ub-ref.rs +++ b/src/test/ui/consts/const-eval/ub-ref.rs @@ -8,9 +8,16 @@ const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; //~^ ERROR it is undefined behavior to use this value //~^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) +const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; +//~^ ERROR it is undefined behavior to use this value +//~^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) + const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + // It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`, // but that would fail to compile; so we ended up breaking user code that would // have worked fine had we not promoted. @@ -20,7 +27,13 @@ const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; //~^ ERROR it is undefined behavior to use this value +const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; +//~^ ERROR it is undefined behavior to use this value + const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; //~^ ERROR it is undefined behavior to use this value +const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; +//~^ ERROR it is undefined behavior to use this value + fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index 5cef0a488ebd7..3cb91ef275236 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -9,13 +9,29 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:11:1 | +LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:15:1 + | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:17:1 + --> $DIR/ub-ref.rs:18:1 + | +LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:24:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -23,7 +39,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:20:1 + --> $DIR/ub-ref.rs:27:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes @@ -31,13 +47,29 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:23:1 + --> $DIR/ub-ref.rs:30:1 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:33:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (created from integer) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -error: aborting due to 5 previous errors +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:36:1 + | +LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (created from integer) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0080`. From f481547622722c4813f6e60bbbe55802dc688664 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 21:03:40 +0100 Subject: [PATCH 14/21] test some more kinds of enums with uninhabited variants --- src/test/ui/consts/const-eval/ub-enum.rs | 36 +++++++++++++- src/test/ui/consts/const-eval/ub-enum.stderr | 52 ++++++++++++++++---- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 4e7c7be4a76ed..1e6a670a40057 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -1,4 +1,4 @@ -#![feature(const_transmute)] +#![feature(const_transmute, never_type)] #![allow(const_err)] // make sure we cannot allow away the errors tested here use std::mem; @@ -7,6 +7,11 @@ use std::mem; #[derive(Copy, Clone)] struct Wrap(T); +#[derive(Copy, Clone)] +enum Never {} + +// # simple enum with discriminant 0 + #[repr(usize)] #[derive(Copy, Clone)] enum Enum { @@ -24,6 +29,8 @@ const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; //~^ ERROR is undefined behavior +// # simple enum with discriminant 2 + // (Potentially) invalid enum discriminant #[repr(usize)] #[derive(Copy, Clone)] @@ -52,11 +59,38 @@ const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; //~^ ERROR is undefined behavior +// # valid discriminant for uninhabited variant + +// An enum with 3 variants of which some are uninhabited -- so the uninhabited variants *do* +// have a discriminant. +enum UninhDiscriminant { + A, + B(!), + C, + D(Never), +} + +const GOOD_INHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(0u8) }; // variant A +const GOOD_INHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(2u8) }; // variant C + +const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; +//~^ ERROR is undefined behavior +const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; +//~^ ERROR is undefined behavior + +// # other + // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). // Need to create something which does not clash with enum layout optimizations. const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); //~^ ERROR is undefined behavior +// All variants are uninhabited but also have data. +const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(1usize) }; +//~^ ERROR is undefined behavior +const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(1usize) }; +//~^ ERROR is undefined behavior + fn main() { } diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 95d4155be91f2..d72884933f5cb 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:18:1 + --> $DIR/ub-enum.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant @@ -7,7 +7,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:21:1 + --> $DIR/ub-enum.rs:26:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes @@ -15,7 +15,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:24:1 + --> $DIR/ub-enum.rs:29:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes @@ -23,7 +23,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:34:1 + --> $DIR/ub-enum.rs:41:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant @@ -31,7 +31,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:36:1 + --> $DIR/ub-enum.rs:43:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes @@ -39,7 +39,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:39:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes @@ -47,7 +47,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:48:1 + --> $DIR/ub-enum.rs:55:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at ., but expected initialized plain (non-pointer) bytes @@ -55,7 +55,7 @@ LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:52:1 + --> $DIR/ub-enum.rs:59:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes @@ -63,13 +63,45 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:58:1 + --> $DIR/ub-enum.rs:76:1 + | +LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at ..0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:78:1 + | +LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at ..0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:86:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected a valid unicode codepoint | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -error: aborting due to 9 previous errors +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:90:1 + | +LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at ..0.1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:92:1 + | +LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at ..0.1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0080`. From 4584e75c9b23b57c4398714406845306e7ba73c2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 21:17:34 +0100 Subject: [PATCH 15/21] better error messages for invalid boxes (and a few more tests) --- src/librustc_mir/interpret/validity.rs | 19 +++++---- src/test/ui/consts/const-eval/ub-ref.rs | 2 +- src/test/ui/consts/const-eval/ub-ref.stderr | 6 +-- src/test/ui/consts/const-eval/ub-wide-ptr.rs | 6 +++ .../ui/consts/const-eval/ub-wide-ptr.stderr | 42 +++++++++++++------ 5 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index ee4d05c5911de..74a22b90a8b81 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -307,7 +307,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M } /// Check a reference or `Box`. - fn check_safe_pointer(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + fn check_safe_pointer( + &mut self, + value: OpTy<'tcx, M::PointerTag>, + kind: &str, + ) -> InterpResult<'tcx> { let value = self.ecx.read_immediate(value)?; // Handle wide pointers. // Check metadata early, for better diagnostics @@ -337,13 +341,14 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M ); match err.kind { err_unsup!(InvalidNullPointerUsage) => { - throw_validation_failure!("a NULL reference", self.path) + throw_validation_failure!(format_args!("a NULL {}", kind), self.path) } err_unsup!(AlignmentCheckFailed { required, has }) => { throw_validation_failure!( format_args!( - "an unaligned reference \ + "an unaligned {} \ (required {} byte alignment but found {})", + kind, required.bytes(), has.bytes() ), @@ -351,11 +356,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M ) } err_unsup!(ReadBytesAsPointer) => throw_validation_failure!( - "a dangling reference (created from integer)", + format_args!("a dangling {} (created from integer)", kind), self.path ), _ => throw_validation_failure!( - "a dangling reference (not entirely in bounds)", + format_args!("a dangling {} (not entirely in bounds)", kind), self.path ), } @@ -449,11 +454,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M Ok(true) } ty::Ref(..) => { - self.check_safe_pointer(value)?; + self.check_safe_pointer(value, "reference")?; Ok(true) } ty::Adt(def, ..) if def.is_box() => { - self.check_safe_pointer(value)?; + self.check_safe_pointer(value, "box")?; Ok(true) } ty::FnPtr(_sig) => { diff --git a/src/test/ui/consts/const-eval/ub-ref.rs b/src/test/ui/consts/const-eval/ub-ref.rs index 14ededafaff04..562ec99111b69 100644 --- a/src/test/ui/consts/const-eval/ub-ref.rs +++ b/src/test/ui/consts/const-eval/ub-ref.rs @@ -10,7 +10,7 @@ const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; //~^ ERROR it is undefined behavior to use this value -//~^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) +//~^^ type validation failed: encountered an unaligned box (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index 3cb91ef275236..fb3df8ace4e15 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -10,7 +10,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:11:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned box (required 2 byte alignment but found 1) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:18:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -66,7 +66,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:36:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (created from integer) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (created from integer) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index ada82fc83a8c7..26d378847462d 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -60,6 +60,12 @@ const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // bad slice: length not an int const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value +// bad slice box: length too big +const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +// bad slice box: length not an int +const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; +//~^ ERROR it is undefined behavior to use this value // bad data *inside* the slice const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr index 2a3ae7dfe6de5..22adf0e55ee8c 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -67,7 +67,23 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:65:1 + --> $DIR/ub-wide-ptr.rs:64:1 + | +LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (not entirely in bounds) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:67:1 + | +LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:71:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected a boolean @@ -75,7 +91,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:71:1 + --> $DIR/ub-wide-ptr.rs:77:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected a boolean @@ -83,7 +99,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:74:1 + --> $DIR/ub-wide-ptr.rs:80:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected a boolean @@ -91,7 +107,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:81:1 + --> $DIR/ub-wide-ptr.rs:87:1 | LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { LL | | @@ -103,7 +119,7 @@ LL | | }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:89:1 + --> $DIR/ub-wide-ptr.rs:95:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -111,7 +127,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:92:1 + --> $DIR/ub-wide-ptr.rs:98:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -119,7 +135,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:95:1 + --> $DIR/ub-wide-ptr.rs:101:1 | LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -127,7 +143,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4u = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:99:1 + --> $DIR/ub-wide-ptr.rs:105:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected a boolean @@ -135,7 +151,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:103:1 + --> $DIR/ub-wide-ptr.rs:109:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -143,7 +159,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:105:1 + --> $DIR/ub-wide-ptr.rs:111:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -151,17 +167,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:111:5 + --> $DIR/ub-wide-ptr.rs:117:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:115:5 + --> $DIR/ub-wide-ptr.rs:121:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N -error: aborting due to 20 previous errors +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0080`. From f0586f9aea1948fe208751f8183d58f9af1116b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 21:53:58 +0100 Subject: [PATCH 16/21] please tidy --- src/test/ui/consts/const-eval/ub-enum.rs | 1 + src/test/ui/consts/const-eval/ub-enum.stderr | 26 ++++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 1e6a670a40057..499be5107f97b 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength #![feature(const_transmute, never_type)] #![allow(const_err)] // make sure we cannot allow away the errors tested here diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index d72884933f5cb..e0cf2cd610fd6 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:23:1 + --> $DIR/ub-enum.rs:24:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant @@ -7,7 +7,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:26:1 + --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes @@ -15,7 +15,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:29:1 + --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes @@ -23,7 +23,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:41:1 + --> $DIR/ub-enum.rs:42:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant @@ -31,7 +31,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:43:1 + --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes @@ -39,7 +39,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:46:1 + --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes @@ -47,7 +47,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:55:1 + --> $DIR/ub-enum.rs:56:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at ., but expected initialized plain (non-pointer) bytes @@ -55,7 +55,7 @@ LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:59:1 + --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes @@ -63,7 +63,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:76:1 + --> $DIR/ub-enum.rs:77:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at ..0 @@ -71,7 +71,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:78:1 + --> $DIR/ub-enum.rs:79:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at ..0 @@ -79,7 +79,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:86:1 + --> $DIR/ub-enum.rs:87:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected a valid unicode codepoint @@ -87,7 +87,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:90:1 + --> $DIR/ub-enum.rs:91:1 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at ..0.1 @@ -95,7 +95,7 @@ LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:92:1 + --> $DIR/ub-enum.rs:93:1 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at ..0.1 From 58f8cc21352613639fdc58f4f8a59f5c579b5372 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:24:23 +0100 Subject: [PATCH 17/21] rename visit_primitive -> try_visit_primitive, and comments --- src/librustc_mir/interpret/validity.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 74a22b90a8b81..29d18e87c4f6e 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -406,7 +406,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M /// Check if this is a value of primitive type, and if yes check the validity of the value /// at that type. Return `true` if the type is indeed primitive. - fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, bool> { + fn try_visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; match ty.kind { @@ -477,7 +477,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M // Nothing to check. Ok(true) } - // This should be all the (inhabited) primitive types. The rest is compound, we + // The above should be all the (inhabited) primitive types. The rest is compound, we // check them by visiting their fields/variants. // (`Str` UTF-8 check happens in `visit_aggregate`, too.) ty::Adt(..) @@ -489,7 +489,8 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => Ok(false), - // Some types only occur during inference, we should not see them here. + // Some types only occur during typechecking, they have no layout. + // We should not see them here and we could not check them anyway. ty::Error | ty::Infer(..) | ty::Placeholder(..) @@ -618,7 +619,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> trace!("visit_value: {:?}, {:?}", *op, op.layout); // Check primitive types -- the leafs of our recursive descend. - if self.visit_primitive(op)? { + if self.try_visit_primitive(op)? { return Ok(()); } // Sanity check: `builtin_deref` does not know any pointers that are not primitive. From 295c2d69bd425e8258f197252d2f100e08f478d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:47:28 +0100 Subject: [PATCH 18/21] bug on ty::GeneratorWitness --- src/librustc_mir/interpret/validity.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 29d18e87c4f6e..0fba8a5c15c4b 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -406,7 +406,10 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M /// Check if this is a value of primitive type, and if yes check the validity of the value /// at that type. Return `true` if the type is indeed primitive. - fn try_visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, bool> { + fn try_visit_primitive( + &mut self, + value: OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; match ty.kind { @@ -487,8 +490,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M | ty::Str | ty::Dynamic(..) | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) => Ok(false), + | ty::Generator(..) => Ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. ty::Error @@ -498,7 +500,8 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M | ty::Param(..) | ty::Opaque(..) | ty::UnnormalizedProjection(..) - | ty::Projection(..) => bug!("Encountered invalid type {:?}", ty), + | ty::Projection(..) + | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty), } } From 1915bf122e488ce540cdb7782550e907f269b9e3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Mar 2020 18:49:13 +0300 Subject: [PATCH 19/21] resolve: `ImportDirective` -> `Import` `ImportDirectiveSubclass` -> `ImportKind` `ImportKind::SingleImport` -> `ImportKind::Single` `ImportKind::GlobImport` -> `ImportKind::Glob` --- src/librustc_resolve/build_reduced_graph.rs | 38 +++--- src/librustc_resolve/check_unused.rs | 10 +- src/librustc_resolve/diagnostics.rs | 10 +- src/librustc_resolve/imports.rs | 132 +++++++++----------- src/librustc_resolve/lib.rs | 40 +++--- 5 files changed, 105 insertions(+), 125 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 43cfe05ac230e..32cf1af60ecda 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -6,8 +6,7 @@ //! Imports are also considered items and placed into modules here, but not resolved yet. use crate::def_collector::collect_definitions; -use crate::imports::ImportDirective; -use crate::imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; +use crate::imports::{Import, ImportKind}; use crate::macros::{LegacyBinding, LegacyScope}; use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; use crate::{CrateLint, Determinacy, PathResult, ResolutionError, VisResolutionError}; @@ -312,7 +311,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn add_import_directive( &mut self, module_path: Vec, - subclass: ImportDirectiveSubclass<'a>, + kind: ImportKind<'a>, span: Span, id: NodeId, item: &ast::Item, @@ -321,11 +320,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { vis: ty::Visibility, ) { let current_module = self.parent_scope.module; - let directive = self.r.arenas.alloc_import_directive(ImportDirective { + let directive = self.r.arenas.alloc_import_directive(Import { + kind, parent_scope: self.parent_scope, module_path, imported_module: Cell::new(None), - subclass, span, id, use_span: item.span, @@ -340,10 +339,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { debug!("add_import_directive({:?})", directive); self.r.indeterminate_imports.push(directive); - match directive.subclass { + match directive.kind { // Don't add unresolved underscore imports to modules - SingleImport { target: Ident { name: kw::Underscore, .. }, .. } => {} - SingleImport { target, type_ns_only, .. } => { + ImportKind::Single { target: Ident { name: kw::Underscore, .. }, .. } => {} + ImportKind::Single { target, type_ns_only, .. } => { self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { let key = this.new_key(target, ns); @@ -354,8 +353,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. - GlobImport { is_prelude: true, .. } => {} - GlobImport { .. } => current_module.globs.borrow_mut().push(directive), + ImportKind::Glob { is_prelude: true, .. } => {} + ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(directive), _ => unreachable!(), } } @@ -480,7 +479,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ); } - let subclass = SingleImport { + let kind = ImportKind::Single { source: source.ident, target: ident, source_bindings: PerNS { @@ -498,7 +497,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }; self.add_import_directive( module_path, - subclass, + kind, use_tree.span, id, item, @@ -508,13 +507,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ); } ast::UseTreeKind::Glob => { - let subclass = GlobImport { + let kind = ImportKind::Glob { is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(ty::Visibility::Invisible), }; self.add_import_directive( prefix, - subclass, + kind, use_tree.span, id, item, @@ -637,15 +636,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let used = self.process_legacy_macro_imports(item, module); let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); - let directive = self.r.arenas.alloc_import_directive(ImportDirective { + let directive = self.r.arenas.alloc_import_directive(Import { + kind: ImportKind::ExternCrate { source: orig_name, target: ident }, root_id: item.id, id: item.id, parent_scope: self.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), - subclass: ImportDirectiveSubclass::ExternCrate { - source: orig_name, - target: ident, - }, has_attributes: !item.attrs.is_empty(), use_span_with_attributes: item.span_with_attributes(), use_span: item.span, @@ -993,12 +989,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } let macro_use_directive = |this: &Self, span| { - this.r.arenas.alloc_import_directive(ImportDirective { + this.r.arenas.alloc_import_directive(Import { + kind: ImportKind::MacroUse, root_id: item.id, id: item.id, parent_scope: this.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), - subclass: ImportDirectiveSubclass::MacroUse, use_span_with_attributes: item.span_with_attributes(), has_attributes: !item.attrs.is_empty(), use_span: item.span, diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 659a54b169b39..5d45fcb39343d 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -23,7 +23,7 @@ // - `check_crate` finally emits the diagnostics based on the data generated // in the last step -use crate::imports::ImportDirectiveSubclass; +use crate::imports::ImportKind; use crate::Resolver; use rustc::{lint, ty}; @@ -224,12 +224,12 @@ fn calc_unused_spans( impl Resolver<'_> { crate fn check_unused(&mut self, krate: &ast::Crate) { for directive in self.potentially_unused_imports.iter() { - match directive.subclass { + match directive.kind { _ if directive.used.get() || directive.vis.get() == ty::Visibility::Public || directive.span.is_dummy() => { - if let ImportDirectiveSubclass::MacroUse = directive.subclass { + if let ImportKind::MacroUse = directive.kind { if !directive.span.is_dummy() { self.lint_buffer.buffer_lint( lint::builtin::MACRO_USE_EXTERN_CRATE, @@ -243,10 +243,10 @@ impl Resolver<'_> { } } } - ImportDirectiveSubclass::ExternCrate { .. } => { + ImportKind::ExternCrate { .. } => { self.maybe_unused_extern_crates.push((directive.id, directive.span)); } - ImportDirectiveSubclass::MacroUse => { + ImportKind::MacroUse => { let lint = lint::builtin::UNUSED_IMPORTS; let msg = "unused `#[macro_use]` import"; self.lint_buffer.buffer_lint(lint, directive.id, directive.span, msg); diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 18192a18cef36..52d50b950005b 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -18,7 +18,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, MultiSpan, Span}; -use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; +use crate::imports::{Import, ImportKind, ImportResolver}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -1126,7 +1126,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// ``` pub(crate) fn check_for_module_export_macro( &mut self, - directive: &'b ImportDirective<'b>, + directive: &'b Import<'b>, module: ModuleOrUniformRoot<'b>, ident: Ident, ) -> Option<(Option, Vec)> { @@ -1151,10 +1151,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { let module_name = crate_module.kind.name().unwrap(); - let import = match directive.subclass { - ImportDirectiveSubclass::SingleImport { source, target, .. } - if source != target => - { + let import = match directive.kind { + ImportKind::Single { source, target, .. } if source != target => { format!("{} as {}", source, target) } _ => format!("{}", ident), diff --git a/src/librustc_resolve/imports.rs b/src/librustc_resolve/imports.rs index 3b018005a88d2..a43ef4ffee46f 100644 --- a/src/librustc_resolve/imports.rs +++ b/src/librustc_resolve/imports.rs @@ -1,7 +1,5 @@ //! A bunch of methods and structures more or less related to resolving imports. -use ImportDirectiveSubclass::*; - use crate::diagnostics::Suggestion; use crate::Determinacy::{self, *}; use crate::Namespace::{self, MacroNS, TypeNS}; @@ -38,8 +36,8 @@ type Res = def::Res; /// Contains data for specific types of import directives. #[derive(Clone, Debug)] -pub enum ImportDirectiveSubclass<'a> { - SingleImport { +pub enum ImportKind<'a> { + Single { /// `source` in `use prefix::source as target`. source: Ident, /// `target` in `use prefix::source as target`. @@ -53,7 +51,7 @@ pub enum ImportDirectiveSubclass<'a> { /// Did this import result from a nested import? ie. `use foo::{bar, baz};` nested: bool, }, - GlobImport { + Glob { is_prelude: bool, max_vis: Cell, // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. @@ -67,10 +65,12 @@ pub enum ImportDirectiveSubclass<'a> { /// One import directive. #[derive(Debug, Clone)] -crate struct ImportDirective<'a> { - /// The ID of the `extern crate`, `UseTree` etc that imported this `ImportDirective`. +crate struct Import<'a> { + pub kind: ImportKind<'a>, + + /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`. /// - /// In the case where the `ImportDirective` was expanded from a "nested" use tree, + /// In the case where the `Import` was expanded from a "nested" use tree, /// this id is the ID of the leaf tree. For example: /// /// ```ignore (pacify the mercilous tidy) @@ -107,22 +107,21 @@ crate struct ImportDirective<'a> { pub module_path: Vec, /// The resolution of `module_path`. pub imported_module: Cell>>, - pub subclass: ImportDirectiveSubclass<'a>, pub vis: Cell, pub used: Cell, } -impl<'a> ImportDirective<'a> { +impl<'a> Import<'a> { pub fn is_glob(&self) -> bool { - match self.subclass { - ImportDirectiveSubclass::GlobImport { .. } => true, + match self.kind { + ImportKind::Glob { .. } => true, _ => false, } } pub fn is_nested(&self) -> bool { - match self.subclass { - ImportDirectiveSubclass::SingleImport { nested, .. } => nested, + match self.kind { + ImportKind::Single { nested, .. } => nested, _ => false, } } @@ -137,7 +136,7 @@ impl<'a> ImportDirective<'a> { pub struct NameResolution<'a> { /// Single imports that may define the name in the namespace. /// Import directives are arena-allocated, so it's ok to use pointers as keys. - single_imports: FxHashSet>>, + single_imports: FxHashSet>>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, shadowed_glob: Option<&'a NameBinding<'a>>, @@ -155,7 +154,7 @@ impl<'a> NameResolution<'a> { }) } - crate fn add_single_import(&mut self, directive: &'a ImportDirective<'a>) { + crate fn add_single_import(&mut self, directive: &'a Import<'a>) { self.single_imports.insert(PtrKey(directive)); } } @@ -348,8 +347,8 @@ impl<'a> Resolver<'a> { single_import.imported_module.get(), return Err((Undetermined, Weak::No)) ); - let ident = match single_import.subclass { - SingleImport { source, .. } => source, + let ident = match single_import.kind { + ImportKind::Single { source, .. } => source, _ => unreachable!(), }; match self.resolve_ident_in_module( @@ -456,7 +455,7 @@ impl<'a> Resolver<'a> { crate fn import( &self, binding: &'a NameBinding<'a>, - directive: &'a ImportDirective<'a>, + directive: &'a Import<'a>, ) -> &'a NameBinding<'a> { let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) || // cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE` @@ -467,7 +466,7 @@ impl<'a> Resolver<'a> { binding.pseudo_vis() }; - if let GlobImport { ref max_vis, .. } = directive.subclass { + if let ImportKind::Glob { ref max_vis, .. } = directive.kind { if vis == directive.vis.get() || vis.is_at_least(max_vis.get(), self) { max_vis.set(vis) } @@ -596,8 +595,8 @@ impl<'a> Resolver<'a> { // Define a "dummy" resolution containing a Res::Err as a placeholder for a // failed resolution - fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) { - if let SingleImport { target, .. } = directive.subclass { + fn import_dummy_binding(&mut self, directive: &'a Import<'a>) { + if let ImportKind::Single { target, .. } = directive.kind { let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, directive); self.per_ns(|this, ns| { @@ -671,7 +670,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { .chain(indeterminate_imports.into_iter().map(|i| (true, i))) { if let Some(err) = self.finalize_import(import) { - if let SingleImport { source, ref source_bindings, .. } = import.subclass { + if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { if source.name == kw::SelfLower { // Silence `unresolved import` error if E0429 is already emitted if let Err(Determined) = source_bindings.value_ns.get() { @@ -695,7 +694,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if seen_spans.insert(err.span) { let path = import_path_to_string( &import.module_path.iter().map(|seg| seg.ident).collect::>(), - &import.subclass, + &import.kind, err.span, ); errors.push((path, err)); @@ -706,7 +705,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { self.r.used_imports.insert((import.id, TypeNS)); let path = import_path_to_string( &import.module_path.iter().map(|seg| seg.ident).collect::>(), - &import.subclass, + &import.kind, import.span, ); let err = UnresolvedImportError { @@ -767,7 +766,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// Attempts to resolve the given import, returning true if its resolution is determined. /// If successful, the resolved bindings are written into the module. - fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool { + fn resolve_import(&mut self, directive: &'b Import<'b>) -> bool { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&directive.module_path), @@ -798,22 +797,22 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }; directive.imported_module.set(Some(module)); - let (source, target, source_bindings, target_bindings, type_ns_only) = - match directive.subclass { - SingleImport { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only), - GlobImport { .. } => { - self.resolve_glob_import(directive); - return true; - } - _ => unreachable!(), - }; + let (source, target, source_bindings, target_bindings, type_ns_only) = match directive.kind + { + ImportKind::Single { + source, + target, + ref source_bindings, + ref target_bindings, + type_ns_only, + .. + } => (source, target, source_bindings, target_bindings, type_ns_only), + ImportKind::Glob { .. } => { + self.resolve_glob_import(directive); + return true; + } + _ => unreachable!(), + }; let mut indeterminate = false; self.r.per_ns(|this, ns| { @@ -873,10 +872,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. - fn finalize_import( - &mut self, - directive: &'b ImportDirective<'b>, - ) -> Option { + fn finalize_import(&mut self, directive: &'b Import<'b>) -> Option { let orig_vis = directive.vis.replace(ty::Visibility::Invisible); let prev_ambiguity_errors_len = self.r.ambiguity_errors.len(); let path_res = self.r.resolve_path( @@ -957,10 +953,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(), }; - let (ident, target, source_bindings, target_bindings, type_ns_only) = match directive - .subclass - { - SingleImport { + let (ident, target, source_bindings, target_bindings, type_ns_only) = match directive.kind { + ImportKind::Single { source, target, ref source_bindings, @@ -968,7 +962,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { type_ns_only, .. } => (source, target, source_bindings, target_bindings, type_ns_only), - GlobImport { is_prelude, ref max_vis } => { + ImportKind::Glob { is_prelude, ref max_vis } => { if directive.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. @@ -1272,7 +1266,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { fn check_for_redundant_imports( &mut self, ident: Ident, - directive: &'b ImportDirective<'b>, + directive: &'b Import<'b>, source_bindings: &PerNS, Determinacy>>>, target_bindings: &PerNS>>>, target: Ident, @@ -1337,7 +1331,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } } - fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) { + fn resolve_glob_import(&mut self, directive: &'b Import<'b>) { let module = match directive.imported_module.get().unwrap() { ModuleOrUniformRoot::Module(module) => module, _ => { @@ -1351,7 +1345,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return; } else if module.def_id() == directive.parent_scope.module.def_id() { return; - } else if let GlobImport { is_prelude: true, .. } = directive.subclass { + } else if let ImportKind::Glob { is_prelude: true, .. } = directive.kind { self.r.prelude = Some(module); return; } @@ -1412,11 +1406,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { && orig_binding.is_variant() && !orig_binding.vis.is_at_least(binding.vis, &*this) { - let msg = match directive.subclass { - ImportDirectiveSubclass::SingleImport { .. } => { + let msg = match directive.kind { + ImportKind::Single { .. } => { format!("variant `{}` is private and cannot be re-exported", ident) } - ImportDirectiveSubclass::GlobImport { .. } => { + ImportKind::Glob { .. } => { let msg = "enum is private and its variants \ cannot be re-exported" .to_owned(); @@ -1432,7 +1426,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } msg } - ref s => bug!("unexpected import subclass {:?}", s), + ref s => bug!("unexpected import kind {:?}", s), }; let mut err = this.session.struct_span_err(binding.span, &msg); @@ -1481,11 +1475,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } } -fn import_path_to_string( - names: &[Ident], - subclass: &ImportDirectiveSubclass<'_>, - span: Span, -) -> String { +fn import_path_to_string(names: &[Ident], import_kind: &ImportKind<'_>, span: Span) -> String { let pos = names.iter().position(|p| span == p.span && p.name != kw::PathRoot); let global = !names.is_empty() && names[0].name == kw::PathRoot; if let Some(pos) = pos { @@ -1494,22 +1484,22 @@ fn import_path_to_string( } else { let names = if global { &names[1..] } else { names }; if names.is_empty() { - import_directive_subclass_to_string(subclass) + import_directive_subclass_to_string(import_kind) } else { format!( "{}::{}", names_to_string(&names.iter().map(|ident| ident.name).collect::>()), - import_directive_subclass_to_string(subclass), + import_directive_subclass_to_string(import_kind), ) } } } -fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass<'_>) -> String { - match *subclass { - SingleImport { source, .. } => source.to_string(), - GlobImport { .. } => "*".to_string(), - ExternCrate { .. } => "".to_string(), - MacroUse => "#[macro_use]".to_string(), +fn import_directive_subclass_to_string(import_kind: &ImportKind<'_>) -> String { + match import_kind { + ImportKind::Single { source, .. } => source.to_string(), + ImportKind::Glob { .. } => "*".to_string(), + ImportKind::ExternCrate { .. } => "".to_string(), + ImportKind::MacroUse => "#[macro_use]".to_string(), } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 44eba0d533d3a..2ffcf340b9a91 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -56,7 +56,7 @@ use std::{cmp, fmt, iter, ptr}; use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding}; use diagnostics::{ImportSuggestion, Suggestion}; -use imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver, NameResolution}; +use imports::{Import, ImportKind, ImportResolver, NameResolution}; use late::{HasGenericParams, PathSource, Rib, RibKind::*}; use macros::{LegacyBinding, LegacyScope}; @@ -456,8 +456,8 @@ pub struct ModuleData<'a> { no_implicit_prelude: bool, - glob_importers: RefCell>>, - globs: RefCell>>, + glob_importers: RefCell>>, + globs: RefCell>>, // Used to memoize the traits in this module for faster searches through all traits in scope. traits: RefCell)]>>>, @@ -584,7 +584,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> { enum NameBindingKind<'a> { Res(Res, /* is_macro_export */ bool), Module(Module<'a>), - Import { binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>, used: Cell }, + Import { binding: &'a NameBinding<'a>, directive: &'a Import<'a>, used: Cell }, } impl<'a> NameBindingKind<'a> { @@ -713,8 +713,7 @@ impl<'a> NameBinding<'a> { fn is_extern_crate(&self) -> bool { match self.kind { NameBindingKind::Import { - directive: - &ImportDirective { subclass: ImportDirectiveSubclass::ExternCrate { .. }, .. }, + directive: &Import { kind: ImportKind::ExternCrate { .. }, .. }, .. } => true, NameBindingKind::Module(&ModuleData { @@ -839,10 +838,10 @@ pub struct Resolver<'a> { field_names: FxHashMap>>, /// All imports known to succeed or fail. - determined_imports: Vec<&'a ImportDirective<'a>>, + determined_imports: Vec<&'a Import<'a>>, /// All non-determined imports. - indeterminate_imports: Vec<&'a ImportDirective<'a>>, + indeterminate_imports: Vec<&'a Import<'a>>, /// FIXME: Refactor things so that these fields are passed through arguments and not resolver. /// We are resolving a last import segment during import validation. @@ -947,7 +946,7 @@ pub struct Resolver<'a> { /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap, - potentially_unused_imports: Vec<&'a ImportDirective<'a>>, + potentially_unused_imports: Vec<&'a Import<'a>>, /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. @@ -971,7 +970,7 @@ pub struct ResolverArenas<'a> { modules: arena::TypedArena>, local_modules: RefCell>>, name_bindings: arena::TypedArena>, - import_directives: arena::TypedArena>, + import_directives: arena::TypedArena>, name_resolutions: arena::TypedArena>>, legacy_bindings: arena::TypedArena>, ast_paths: arena::TypedArena, @@ -991,10 +990,7 @@ impl<'a> ResolverArenas<'a> { fn alloc_name_binding(&'a self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> { self.name_bindings.alloc(name_binding) } - fn alloc_import_directive( - &'a self, - import_directive: ImportDirective<'a>, - ) -> &'a ImportDirective<'_> { + fn alloc_import_directive(&'a self, import_directive: Import<'a>) -> &'a Import<'_> { self.import_directives.alloc(import_directive) } fn alloc_name_resolution(&'a self) -> &'a RefCell> { @@ -1431,7 +1427,7 @@ impl<'a> Resolver<'a> { } #[inline] - fn add_to_glob_map(&mut self, directive: &ImportDirective<'_>, ident: Ident) { + fn add_to_glob_map(&mut self, directive: &Import<'_>, ident: Ident) { if directive.is_glob() { self.glob_map.entry(directive.id).or_default().insert(ident.name); } @@ -2261,7 +2257,7 @@ impl<'a> Resolver<'a> { if let NameBindingKind::Import { directive: d, .. } = binding.kind { // Careful: we still want to rewrite paths from // renamed extern crates. - if let ImportDirectiveSubclass::ExternCrate { source: None, .. } = d.subclass { + if let ImportKind::ExternCrate { source: None, .. } = d.kind { return; } } @@ -2639,7 +2635,7 @@ impl<'a> Resolver<'a> { &self, err: &mut DiagnosticBuilder<'_>, name: Name, - directive: &ImportDirective<'_>, + directive: &Import<'_>, binding_span: Span, ) { let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { @@ -2649,11 +2645,11 @@ impl<'a> Resolver<'a> { }; let mut suggestion = None; - match directive.subclass { - ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } => { + match directive.kind { + ImportKind::Single { type_ns_only: true, .. } => { suggestion = Some(format!("self as {}", suggested_name)) } - ImportDirectiveSubclass::SingleImport { source, .. } => { + ImportKind::Single { source, .. } => { if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize) { @@ -2669,7 +2665,7 @@ impl<'a> Resolver<'a> { } } } - ImportDirectiveSubclass::ExternCrate { source, target, .. } => { + ImportKind::ExternCrate { source, target, .. } => { suggestion = Some(format!( "extern crate {} as {};", source.unwrap_or(target.name), @@ -2717,7 +2713,7 @@ impl<'a> Resolver<'a> { fn add_suggestion_for_duplicate_nested_use( &self, err: &mut DiagnosticBuilder<'_>, - directive: &ImportDirective<'_>, + directive: &Import<'_>, binding_span: Span, ) { assert!(directive.is_nested()); From 66d7a88c41ebcc25e499babd103177a9d8df6cdb Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Mar 2020 19:02:32 +0300 Subject: [PATCH 20/21] resolve: `directive` -> `import` --- src/librustc_resolve/build_reduced_graph.rs | 51 ++-- src/librustc_resolve/check_unused.rs | 30 +- src/librustc_resolve/diagnostics.rs | 18 +- src/librustc_resolve/imports.rs | 264 +++++++++--------- src/librustc_resolve/late.rs | 8 +- src/librustc_resolve/lib.rs | 77 +++-- .../ui/rust-2018/macro-use-warned-against.rs | 2 +- .../rust-2018/macro-use-warned-against.stderr | 2 +- 8 files changed, 215 insertions(+), 237 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 32cf1af60ecda..ec5a8c4a0b896 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -307,8 +307,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }) } - // Add an import directive to the current module. - fn add_import_directive( + // Add an import to the current module. + fn add_import( &mut self, module_path: Vec, kind: ImportKind<'a>, @@ -320,7 +320,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { vis: ty::Visibility, ) { let current_module = self.parent_scope.module; - let directive = self.r.arenas.alloc_import_directive(Import { + let import = self.r.arenas.alloc_import(Import { kind, parent_scope: self.parent_scope, module_path, @@ -336,10 +336,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { used: Cell::new(false), }); - debug!("add_import_directive({:?})", directive); + debug!("add_import({:?})", import); - self.r.indeterminate_imports.push(directive); - match directive.kind { + self.r.indeterminate_imports.push(import); + match import.kind { // Don't add unresolved underscore imports to modules ImportKind::Single { target: Ident { name: kw::Underscore, .. }, .. } => {} ImportKind::Single { target, type_ns_only, .. } => { @@ -347,14 +347,14 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if !type_ns_only || ns == TypeNS { let key = this.new_key(target, ns); let mut resolution = this.resolution(current_module, key).borrow_mut(); - resolution.add_single_import(directive); + resolution.add_single_import(import); } }); } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. ImportKind::Glob { is_prelude: true, .. } => {} - ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(directive), + ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import), _ => unreachable!(), } } @@ -495,7 +495,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { type_ns_only, nested, }; - self.add_import_directive( + self.add_import( module_path, kind, use_tree.span, @@ -511,16 +511,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(ty::Visibility::Invisible), }; - self.add_import_directive( - prefix, - kind, - use_tree.span, - id, - item, - root_span, - item.id, - vis, - ); + self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis); } ast::UseTreeKind::Nested(ref items) => { // Ensure there is at most one `self` in the list @@ -636,7 +627,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let used = self.process_legacy_macro_imports(item, module); let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); - let directive = self.r.arenas.alloc_import_directive(Import { + let import = self.r.arenas.alloc_import(Import { kind: ImportKind::ExternCrate { source: orig_name, target: ident }, root_id: item.id, id: item.id, @@ -651,8 +642,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { vis: Cell::new(vis), used: Cell::new(used), }); - self.r.potentially_unused_imports.push(directive); - let imported_binding = self.r.import(binding, directive); + self.r.potentially_unused_imports.push(import); + let imported_binding = self.r.import(binding, import); if ptr::eq(parent, self.r.graph_root) { if let Some(entry) = self.r.extern_prelude.get(&ident.modern()) { if expansion != ExpnId::root() @@ -988,8 +979,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } } - let macro_use_directive = |this: &Self, span| { - this.r.arenas.alloc_import_directive(Import { + let macro_use_import = |this: &Self, span| { + this.r.arenas.alloc_import(Import { kind: ImportKind::MacroUse, root_id: item.id, id: item.id, @@ -1008,11 +999,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let allow_shadowing = self.parent_scope.expansion == ExpnId::root(); if let Some(span) = import_all { - let directive = macro_use_directive(self, span); - self.r.potentially_unused_imports.push(directive); + let import = macro_use_import(self, span); + self.r.potentially_unused_imports.push(import); module.for_each_child(self, |this, ident, ns, binding| { if ns == MacroNS { - let imported_binding = this.r.import(binding, directive); + let imported_binding = this.r.import(binding, import); this.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); } }); @@ -1027,9 +1018,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ident.span, ); if let Ok(binding) = result { - let directive = macro_use_directive(self, ident.span); - self.r.potentially_unused_imports.push(directive); - let imported_binding = self.r.import(binding, directive); + let import = macro_use_import(self, ident.span); + self.r.potentially_unused_imports.push(import); + let imported_binding = self.r.import(binding, import); self.legacy_import_macro( ident.name, imported_binding, diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 5d45fcb39343d..722f843ab6e7e 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -3,7 +3,7 @@ // // Although this is mostly a lint pass, it lives in here because it depends on // resolve data structures and because it finalises the privacy information for -// `use` directives. +// `use` items. // // Unused trait imports can't be checked until the method resolution. We save // candidates here, and do the actual check in librustc_typeck/check_unused.rs. @@ -58,7 +58,7 @@ struct UnusedImportCheckVisitor<'a, 'b> { } impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { - // We have information about whether `use` (import) directives are actually + // We have information about whether `use` (import) items are actually // used now. If an import is not used at all, we signal a lint error. fn check_import(&mut self, id: ast::NodeId) { let mut used = false; @@ -223,33 +223,33 @@ fn calc_unused_spans( impl Resolver<'_> { crate fn check_unused(&mut self, krate: &ast::Crate) { - for directive in self.potentially_unused_imports.iter() { - match directive.kind { - _ if directive.used.get() - || directive.vis.get() == ty::Visibility::Public - || directive.span.is_dummy() => + for import in self.potentially_unused_imports.iter() { + match import.kind { + _ if import.used.get() + || import.vis.get() == ty::Visibility::Public + || import.span.is_dummy() => { - if let ImportKind::MacroUse = directive.kind { - if !directive.span.is_dummy() { + if let ImportKind::MacroUse = import.kind { + if !import.span.is_dummy() { self.lint_buffer.buffer_lint( lint::builtin::MACRO_USE_EXTERN_CRATE, - directive.id, - directive.span, - "deprecated `#[macro_use]` directive used to \ + import.id, + import.span, + "deprecated `#[macro_use]` attribute used to \ import macros should be replaced at use sites \ - with a `use` statement to import the macro \ + with a `use` item to import the macro \ instead", ); } } } ImportKind::ExternCrate { .. } => { - self.maybe_unused_extern_crates.push((directive.id, directive.span)); + self.maybe_unused_extern_crates.push((import.id, import.span)); } ImportKind::MacroUse => { let lint = lint::builtin::UNUSED_IMPORTS; let msg = "unused `#[macro_use]` import"; - self.lint_buffer.buffer_lint(lint, directive.id, directive.span, msg); + self.lint_buffer.buffer_lint(lint, import.id, import.span, msg); } _ => {} } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 52d50b950005b..38efc907ff077 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1126,7 +1126,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// ``` pub(crate) fn check_for_module_export_macro( &mut self, - directive: &'b Import<'b>, + import: &'b Import<'b>, module: ModuleOrUniformRoot<'b>, ident: Ident, ) -> Option<(Option, Vec)> { @@ -1151,7 +1151,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { let module_name = crate_module.kind.name().unwrap(); - let import = match directive.kind { + let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { format!("{} as {}", source, target) } @@ -1159,18 +1159,18 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }; let mut corrections: Vec<(Span, String)> = Vec::new(); - if !directive.is_nested() { + if !import.is_nested() { // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove // intermediate segments. - corrections.push((directive.span, format!("{}::{}", module_name, import))); + corrections.push((import.span, format!("{}::{}", module_name, import_snippet))); } else { // Find the binding span (and any trailing commas and spaces). // ie. `use a::b::{c, d, e};` // ^^^ let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( self.r.session, - directive.span, - directive.use_span, + import.span, + import.use_span, ); debug!( "check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}", @@ -1207,7 +1207,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( self.r.session, module_name, - directive.use_span, + import.use_span, ); debug!( "check_for_module_export_macro: has_nested={:?} after_crate_name={:?}", @@ -1223,11 +1223,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { start_point, if has_nested { // In this case, `start_snippet` must equal '{'. - format!("{}{}, ", start_snippet, import) + format!("{}{}, ", start_snippet, import_snippet) } else { // In this case, add a `{`, then the moved import, then whatever // was there before. - format!("{{{}, {}", import, start_snippet) + format!("{{{}, {}", import_snippet, start_snippet) }, )); } diff --git a/src/librustc_resolve/imports.rs b/src/librustc_resolve/imports.rs index a43ef4ffee46f..81c1e496c9d5f 100644 --- a/src/librustc_resolve/imports.rs +++ b/src/librustc_resolve/imports.rs @@ -34,7 +34,7 @@ use std::{mem, ptr}; type Res = def::Res; -/// Contains data for specific types of import directives. +/// Contains data for specific kinds of imports. #[derive(Clone, Debug)] pub enum ImportKind<'a> { Single { @@ -63,7 +63,7 @@ pub enum ImportKind<'a> { MacroUse, } -/// One import directive. +/// One import. #[derive(Debug, Clone)] crate struct Import<'a> { pub kind: ImportKind<'a>, @@ -77,7 +77,7 @@ crate struct Import<'a> { /// use foo::bar::{a, b} /// ``` /// - /// If this is the import directive for `foo::bar::a`, we would have the ID of the `UseTree` + /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` /// for `a` in this field. pub id: NodeId, @@ -135,7 +135,7 @@ impl<'a> Import<'a> { /// Records information about the resolution of a name in a namespace of a module. pub struct NameResolution<'a> { /// Single imports that may define the name in the namespace. - /// Import directives are arena-allocated, so it's ok to use pointers as keys. + /// Imports are arena-allocated, so it's ok to use pointers as keys. single_imports: FxHashSet>>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, @@ -154,8 +154,8 @@ impl<'a> NameResolution<'a> { }) } - crate fn add_single_import(&mut self, directive: &'a Import<'a>) { - self.single_imports.insert(PtrKey(directive)); + crate fn add_single_import(&mut self, import: &'a Import<'a>) { + self.single_imports.insert(PtrKey(import)); } } @@ -450,34 +450,34 @@ impl<'a> Resolver<'a> { Err((Determined, Weak::No)) } - // Given a binding and an import directive that resolves to it, - // return the corresponding binding defined by the import directive. + // Given a binding and an import that resolves to it, + // return the corresponding binding defined by the import. crate fn import( &self, binding: &'a NameBinding<'a>, - directive: &'a Import<'a>, + import: &'a Import<'a>, ) -> &'a NameBinding<'a> { - let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) || + let vis = if binding.pseudo_vis().is_at_least(import.vis.get(), self) || // cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE` - !directive.is_glob() && binding.is_extern_crate() + !import.is_glob() && binding.is_extern_crate() { - directive.vis.get() + import.vis.get() } else { binding.pseudo_vis() }; - if let ImportKind::Glob { ref max_vis, .. } = directive.kind { - if vis == directive.vis.get() || vis.is_at_least(max_vis.get(), self) { + if let ImportKind::Glob { ref max_vis, .. } = import.kind { + if vis == import.vis.get() || vis.is_at_least(max_vis.get(), self) { max_vis.set(vis) } } self.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Import { binding, directive, used: Cell::new(false) }, + kind: NameBindingKind::Import { binding, import, used: Cell::new(false) }, ambiguity: None, - span: directive.span, + span: import.span, vis, - expansion: directive.parent_scope.expansion, + expansion: import.parent_scope.expansion, }) } @@ -576,17 +576,17 @@ impl<'a> Resolver<'a> { }; // Define `binding` in `module`s glob importers. - for directive in module.glob_importers.borrow_mut().iter() { + for import in module.glob_importers.borrow_mut().iter() { let mut ident = key.ident; - let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { + let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.macro_def_scope(def), - Some(None) => directive.parent_scope.module, + Some(None) => import.parent_scope.module, None => continue, }; if self.is_accessible_from(binding.vis, scope) { - let imported_binding = self.import(binding, directive); + let imported_binding = self.import(binding, import); let key = BindingKey { ident, ..key }; - let _ = self.try_define(directive.parent_scope.module, key, imported_binding); + let _ = self.try_define(import.parent_scope.module, key, imported_binding); } } @@ -595,13 +595,13 @@ impl<'a> Resolver<'a> { // Define a "dummy" resolution containing a Res::Err as a placeholder for a // failed resolution - fn import_dummy_binding(&mut self, directive: &'a Import<'a>) { - if let ImportKind::Single { target, .. } = directive.kind { + fn import_dummy_binding(&mut self, import: &'a Import<'a>) { + if let ImportKind::Single { target, .. } = import.kind { let dummy_binding = self.dummy_binding; - let dummy_binding = self.import(dummy_binding, directive); + let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { let key = this.new_key(target, ns); - let _ = this.try_define(directive.parent_scope.module, key, dummy_binding); + let _ = this.try_define(import.parent_scope.module, key, dummy_binding); // Consider erroneous imports used to avoid duplicate diagnostics. this.record_use(target, ns, dummy_binding, false); }); @@ -766,28 +766,28 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// Attempts to resolve the given import, returning true if its resolution is determined. /// If successful, the resolved bindings are written into the module. - fn resolve_import(&mut self, directive: &'b Import<'b>) -> bool { + fn resolve_import(&mut self, import: &'b Import<'b>) -> bool { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", - Segment::names_to_string(&directive.module_path), - module_to_string(directive.parent_scope.module).unwrap_or_else(|| "???".to_string()), + Segment::names_to_string(&import.module_path), + module_to_string(import.parent_scope.module).unwrap_or_else(|| "???".to_string()), ); - let module = if let Some(module) = directive.imported_module.get() { + let module = if let Some(module) = import.imported_module.get() { module } else { // For better failure detection, pretend that the import will // not define any names while resolving its module path. - let orig_vis = directive.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.replace(ty::Visibility::Invisible); let path_res = self.r.resolve_path( - &directive.module_path, + &import.module_path, None, - &directive.parent_scope, + &import.parent_scope, false, - directive.span, - directive.crate_lint(), + import.span, + import.crate_lint(), ); - directive.vis.set(orig_vis); + import.vis.set(orig_vis); match path_res { PathResult::Module(module) => module, @@ -796,9 +796,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } }; - directive.imported_module.set(Some(module)); - let (source, target, source_bindings, target_bindings, type_ns_only) = match directive.kind - { + import.imported_module.set(Some(module)); + let (source, target, source_bindings, target_bindings, type_ns_only) = match import.kind { ImportKind::Single { source, target, @@ -808,7 +807,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { .. } => (source, target, source_bindings, target_bindings, type_ns_only), ImportKind::Glob { .. } => { - self.resolve_glob_import(directive); + self.resolve_glob_import(import); return true; } _ => unreachable!(), @@ -820,23 +819,23 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let Err(Undetermined) = source_bindings[ns].get() { // For better failure detection, pretend that the import will // not define any names while resolving its module path. - let orig_vis = directive.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.replace(ty::Visibility::Invisible); let binding = this.resolve_ident_in_module( module, source, ns, - &directive.parent_scope, + &import.parent_scope, false, - directive.span, + import.span, ); - directive.vis.set(orig_vis); + import.vis.set(orig_vis); source_bindings[ns].set(binding); } else { return; }; - let parent = directive.parent_scope.module; + let parent = import.parent_scope.module; match source_bindings[ns].get() { Err(Undetermined) => indeterminate = true, // Don't update the resolution, because it was never added. @@ -844,20 +843,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> { Err(Determined) => { let key = this.new_key(target, ns); this.update_resolution(parent, key, |_, resolution| { - resolution.single_imports.remove(&PtrKey(directive)); + resolution.single_imports.remove(&PtrKey(import)); }); } Ok(binding) if !binding.is_importable() => { let msg = format!("`{}` is not directly importable", target); - struct_span_err!(this.session, directive.span, E0253, "{}", &msg) - .span_label(directive.span, "cannot be imported directly") + struct_span_err!(this.session, import.span, E0253, "{}", &msg) + .span_label(import.span, "cannot be imported directly") .emit(); // Do not import this illegal binding. Import a dummy binding and pretend // everything is fine - this.import_dummy_binding(directive); + this.import_dummy_binding(import); } Ok(binding) => { - let imported_binding = this.import(binding, directive); + let imported_binding = this.import(binding, import); target_bindings[ns].set(Some(imported_binding)); this.define(parent, target, ns, imported_binding); } @@ -872,35 +871,35 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. - fn finalize_import(&mut self, directive: &'b Import<'b>) -> Option { - let orig_vis = directive.vis.replace(ty::Visibility::Invisible); + fn finalize_import(&mut self, import: &'b Import<'b>) -> Option { + let orig_vis = import.vis.replace(ty::Visibility::Invisible); let prev_ambiguity_errors_len = self.r.ambiguity_errors.len(); let path_res = self.r.resolve_path( - &directive.module_path, + &import.module_path, None, - &directive.parent_scope, + &import.parent_scope, true, - directive.span, - directive.crate_lint(), + import.span, + import.crate_lint(), ); let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; - directive.vis.set(orig_vis); + import.vis.set(orig_vis); if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res { // Consider erroneous imports used to avoid duplicate diagnostics. - self.r.used_imports.insert((directive.id, TypeNS)); + self.r.used_imports.insert((import.id, TypeNS)); } let module = match path_res { PathResult::Module(module) => { // Consistency checks, analogous to `finalize_macro_resolutions`. - if let Some(initial_module) = directive.imported_module.get() { + if let Some(initial_module) = import.imported_module.get() { if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity { - span_bug!(directive.span, "inconsistent resolution for an import"); + span_bug!(import.span, "inconsistent resolution for an import"); } } else { if self.r.privacy_errors.is_empty() { let msg = "cannot determine resolution for the import"; let msg_note = "import resolution is stuck, try simplifying other imports"; - self.r.session.struct_span_err(directive.span, msg).note(msg_note).emit(); + self.r.session.struct_span_err(import.span, msg).note(msg_note).emit(); } } @@ -908,7 +907,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { if no_ambiguity { - assert!(directive.imported_module.get().is_none()); + assert!(import.imported_module.get().is_none()); self.r .report_error(span, ResolutionError::FailedToResolve { label, suggestion }); } @@ -916,11 +915,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => { if no_ambiguity { - assert!(directive.imported_module.get().is_none()); + assert!(import.imported_module.get().is_none()); let err = match self.make_path_suggestion( span, - directive.module_path.clone(), - &directive.parent_scope, + import.module_path.clone(), + &import.parent_scope, ) { Some((suggestion, note)) => UnresolvedImportError { span, @@ -945,7 +944,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } PathResult::NonModule(path_res) if path_res.base_res() == Res::Err => { if no_ambiguity { - assert!(directive.imported_module.get().is_none()); + assert!(import.imported_module.get().is_none()); } // The error was already reported earlier. return None; @@ -953,7 +952,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(), }; - let (ident, target, source_bindings, target_bindings, type_ns_only) = match directive.kind { + let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind { ImportKind::Single { source, target, @@ -963,24 +962,24 @@ impl<'a, 'b> ImportResolver<'a, 'b> { .. } => (source, target, source_bindings, target_bindings, type_ns_only), ImportKind::Glob { is_prelude, ref max_vis } => { - if directive.module_path.len() <= 1 { + if import.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. - let mut full_path = directive.module_path.clone(); + let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(Ident::invalid())); self.r.lint_if_path_starts_with_module( - directive.crate_lint(), + import.crate_lint(), &full_path, - directive.span, + import.span, None, ); } if let ModuleOrUniformRoot::Module(module) = module { - if module.def_id() == directive.parent_scope.module.def_id() { + if module.def_id() == import.parent_scope.module.def_id() { // Importing a module into itself is not allowed. return Some(UnresolvedImportError { - span: directive.span, + span: import.span, label: Some(String::from("cannot glob-import a module into itself")), note: Vec::new(), suggestion: None, @@ -989,15 +988,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } if !is_prelude && max_vis.get() != ty::Visibility::Invisible && // Allow empty globs. - !max_vis.get().is_at_least(directive.vis.get(), &*self) + !max_vis.get().is_at_least(import.vis.get(), &*self) { let msg = "glob import doesn't reexport anything because no candidate is public enough"; - self.r.lint_buffer.buffer_lint( - UNUSED_IMPORTS, - directive.id, - directive.span, - msg, - ); + self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); } return None; } @@ -1007,7 +1001,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut all_ns_err = true; self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let orig_vis = directive.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.replace(ty::Visibility::Invisible); let orig_blacklisted_binding = mem::replace(&mut this.blacklisted_binding, target_bindings[ns].get()); let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true); @@ -1015,13 +1009,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> { module, ident, ns, - &directive.parent_scope, + &import.parent_scope, true, - directive.span, + import.span, ); this.last_import_segment = orig_last_import_segment; this.blacklisted_binding = orig_blacklisted_binding; - directive.vis.set(orig_vis); + import.vis.set(orig_vis); match binding { Ok(binding) => { @@ -1038,7 +1032,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ident, ns, target_binding, - directive.module_path.is_empty(), + import.module_path.is_empty(), ); } } @@ -1047,7 +1041,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let res = binding.res(); if let Ok(initial_res) = initial_res { if res != initial_res && this.ambiguity_errors.is_empty() { - span_bug!(directive.span, "inconsistent resolution for an import"); + span_bug!(import.span, "inconsistent resolution for an import"); } } else { if res != Res::Err @@ -1058,7 +1052,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let msg_note = "import resolution is stuck, try simplifying other imports"; this.session - .struct_span_err(directive.span, msg) + .struct_span_err(import.span, msg) .note(msg_note) .emit(); } @@ -1084,9 +1078,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { module, ident, ns, - &directive.parent_scope, + &import.parent_scope, true, - directive.span, + import.span, ); if binding.is_ok() { all_ns_failed = false; @@ -1137,7 +1131,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }); let (suggestion, note) = - match self.check_for_module_export_macro(directive, module, ident) { + match self.check_for_module_export_macro(import, module, ident) { Some((suggestion, note)) => (suggestion.or(lev_suggestion), note), _ => (lev_suggestion, Vec::new()), }; @@ -1163,14 +1157,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }; Some(UnresolvedImportError { - span: directive.span, + span: import.span, label: Some(label), note, suggestion, }) } else { // `resolve_ident_in_module` reported a privacy error. - self.r.import_dummy_binding(directive); + self.r.import_dummy_binding(import); None }; } @@ -1179,7 +1173,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut any_successful_reexport = false; self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { - let vis = directive.vis.get(); + let vis = import.vis.get(); if !binding.pseudo_vis().is_at_least(vis, &*this) { reexport_error = Some((ns, binding)); } else { @@ -1200,42 +1194,42 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ); self.r.lint_buffer.buffer_lint( PUB_USE_OF_PRIVATE_EXTERN_CRATE, - directive.id, - directive.span, + import.id, + import.span, &msg, ); } else if ns == TypeNS { struct_span_err!( self.r.session, - directive.span, + import.span, E0365, "`{}` is private, and cannot be re-exported", ident ) - .span_label(directive.span, format!("re-export of private `{}`", ident)) + .span_label(import.span, format!("re-export of private `{}`", ident)) .note(&format!("consider declaring type or module `{}` with `pub`", ident)) .emit(); } else { let msg = format!("`{}` is private, and cannot be re-exported", ident); let note_msg = format!("consider marking `{}` as `pub` in the imported module", ident,); - struct_span_err!(self.r.session, directive.span, E0364, "{}", &msg) - .span_note(directive.span, ¬e_msg) + struct_span_err!(self.r.session, import.span, E0364, "{}", &msg) + .span_note(import.span, ¬e_msg) .emit(); } } - if directive.module_path.len() <= 1 { + if import.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. - let mut full_path = directive.module_path.clone(); + let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { this.lint_if_path_starts_with_module( - directive.crate_lint(), + import.crate_lint(), &full_path, - directive.span, + import.span, Some(binding), ); } @@ -1247,17 +1241,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // purposes it's good enough to just favor one over the other. self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { - this.import_res_map.entry(directive.id).or_default()[ns] = Some(binding.res()); + this.import_res_map.entry(import.id).or_default()[ns] = Some(binding.res()); } }); - self.check_for_redundant_imports( - ident, - directive, - source_bindings, - target_bindings, - target, - ); + self.check_for_redundant_imports(ident, import, source_bindings, target_bindings, target); debug!("(resolving single import) successfully resolved import"); None @@ -1266,19 +1254,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> { fn check_for_redundant_imports( &mut self, ident: Ident, - directive: &'b Import<'b>, + import: &'b Import<'b>, source_bindings: &PerNS, Determinacy>>>, target_bindings: &PerNS>>>, target: Ident, ) { // Skip if the import was produced by a macro. - if directive.parent_scope.expansion != ExpnId::root() { + if import.parent_scope.expansion != ExpnId::root() { return; } // Skip if we are inside a named module (in contrast to an anonymous // module defined by a block). - if let ModuleKind::Def(..) = directive.parent_scope.module.kind { + if let ModuleKind::Def(..) = import.parent_scope.module.kind { return; } @@ -1298,10 +1286,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { match this.early_resolve_ident_in_lexical_scope( target, ScopeSet::All(ns, false), - &directive.parent_scope, + &import.parent_scope, false, false, - directive.span, + import.span, ) { Ok(other_binding) => { is_redundant[ns] = Some( @@ -1323,35 +1311,35 @@ impl<'a, 'b> ImportResolver<'a, 'b> { redundant_spans.dedup(); self.r.lint_buffer.buffer_lint_with_diagnostic( UNUSED_IMPORTS, - directive.id, - directive.span, + import.id, + import.span, &format!("the item `{}` is imported redundantly", ident), BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident), ); } } - fn resolve_glob_import(&mut self, directive: &'b Import<'b>) { - let module = match directive.imported_module.get().unwrap() { + fn resolve_glob_import(&mut self, import: &'b Import<'b>) { + let module = match import.imported_module.get().unwrap() { ModuleOrUniformRoot::Module(module) => module, _ => { - self.r.session.span_err(directive.span, "cannot glob-import all possible crates"); + self.r.session.span_err(import.span, "cannot glob-import all possible crates"); return; } }; if module.is_trait() { - self.r.session.span_err(directive.span, "items in traits are not importable."); + self.r.session.span_err(import.span, "items in traits are not importable."); return; - } else if module.def_id() == directive.parent_scope.module.def_id() { + } else if module.def_id() == import.parent_scope.module.def_id() { return; - } else if let ImportKind::Glob { is_prelude: true, .. } = directive.kind { + } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind { self.r.prelude = Some(module); return; } // Add to module's glob_importers - module.glob_importers.borrow_mut().push(directive); + module.glob_importers.borrow_mut().push(import); // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. @@ -1365,19 +1353,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }) .collect::>(); for (mut key, binding) in bindings { - let scope = match key.ident.span.reverse_glob_adjust(module.expansion, directive.span) { + let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.r.macro_def_scope(def), - Some(None) => directive.parent_scope.module, + Some(None) => import.parent_scope.module, None => continue, }; if self.r.is_accessible_from(binding.pseudo_vis(), scope) { - let imported_binding = self.r.import(binding, directive); - let _ = self.r.try_define(directive.parent_scope.module, key, imported_binding); + let imported_binding = self.r.import(binding, import); + let _ = self.r.try_define(import.parent_scope.module, key, imported_binding); } } // Record the destination of this import - self.r.record_partial_res(directive.id, PartialRes::new(module.res().unwrap())); + self.r.record_partial_res(import.id, PartialRes::new(module.res().unwrap())); } // Miscellaneous post-processing, including recording re-exports, @@ -1401,12 +1389,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } } - if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { + if let NameBindingKind::Import { binding: orig_binding, import, .. } = binding.kind { if ns == TypeNS && orig_binding.is_variant() && !orig_binding.vis.is_at_least(binding.vis, &*this) { - let msg = match directive.kind { + let msg = match import.kind { ImportKind::Single { .. } => { format!("variant `{}` is private and cannot be re-exported", ident) } @@ -1430,14 +1418,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }; let mut err = this.session.struct_span_err(binding.span, &msg); - let imported_module = match directive.imported_module.get() { + let imported_module = match import.imported_module.get() { Some(ModuleOrUniformRoot::Module(module)) => module, _ => bug!("module should exist"), }; let parent_module = imported_module.parent.expect("parent should exist"); let resolutions = this.resolutions(parent_module).borrow(); - let enum_path_segment_index = directive.module_path.len() - 1; - let enum_ident = directive.module_path[enum_path_segment_index].ident; + let enum_path_segment_index = import.module_path.len() - 1; + let enum_ident = import.module_path[enum_path_segment_index].ident; let key = this.new_key(enum_ident, TypeNS); let enum_resolution = resolutions.get(&key).expect("resolution should exist"); @@ -1484,18 +1472,18 @@ fn import_path_to_string(names: &[Ident], import_kind: &ImportKind<'_>, span: Sp } else { let names = if global { &names[1..] } else { names }; if names.is_empty() { - import_directive_subclass_to_string(import_kind) + import_kind_to_string(import_kind) } else { format!( "{}::{}", names_to_string(&names.iter().map(|ident| ident.name).collect::>()), - import_directive_subclass_to_string(import_kind), + import_kind_to_string(import_kind), ) } } } -fn import_directive_subclass_to_string(import_kind: &ImportKind<'_>) -> String { +fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String { match import_kind { ImportKind::Single { source, .. } => source.to_string(), ImportKind::Glob { .. } => "*".to_string(), diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 6b5e927214f5a..98bb98a3a8dac 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -2189,10 +2189,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { trait_name: Ident, ) -> SmallVec<[NodeId; 1]> { let mut import_ids = smallvec![]; - while let NameBindingKind::Import { directive, binding, .. } = kind { - self.r.maybe_unused_trait_imports.insert(directive.id); - self.r.add_to_glob_map(&directive, trait_name); - import_ids.push(directive.id); + while let NameBindingKind::Import { import, binding, .. } = kind { + self.r.maybe_unused_trait_imports.insert(import.id); + self.r.add_to_glob_map(&import, trait_name); + import_ids.push(import.id); kind = &binding.kind; } import_ids diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2ffcf340b9a91..492ac6ed83977 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -584,7 +584,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> { enum NameBindingKind<'a> { Res(Res, /* is_macro_export */ bool), Module(Module<'a>), - Import { binding: &'a NameBinding<'a>, directive: &'a Import<'a>, used: Cell }, + Import { binding: &'a NameBinding<'a>, import: &'a Import<'a>, used: Cell }, } impl<'a> NameBindingKind<'a> { @@ -713,7 +713,7 @@ impl<'a> NameBinding<'a> { fn is_extern_crate(&self) -> bool { match self.kind { NameBindingKind::Import { - directive: &Import { kind: ImportKind::ExternCrate { .. }, .. }, + import: &Import { kind: ImportKind::ExternCrate { .. }, .. }, .. } => true, NameBindingKind::Module(&ModuleData { @@ -733,7 +733,7 @@ impl<'a> NameBinding<'a> { fn is_glob_import(&self) -> bool { match self.kind { - NameBindingKind::Import { directive, .. } => directive.is_glob(), + NameBindingKind::Import { import, .. } => import.is_glob(), _ => false, } } @@ -970,7 +970,7 @@ pub struct ResolverArenas<'a> { modules: arena::TypedArena>, local_modules: RefCell>>, name_bindings: arena::TypedArena>, - import_directives: arena::TypedArena>, + imports: arena::TypedArena>, name_resolutions: arena::TypedArena>>, legacy_bindings: arena::TypedArena>, ast_paths: arena::TypedArena, @@ -990,8 +990,8 @@ impl<'a> ResolverArenas<'a> { fn alloc_name_binding(&'a self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> { self.name_bindings.alloc(name_binding) } - fn alloc_import_directive(&'a self, import_directive: Import<'a>) -> &'a Import<'_> { - self.import_directives.alloc(import_directive) + fn alloc_import(&'a self, import: Import<'a>) -> &'a Import<'_> { + self.imports.alloc(import) } fn alloc_name_resolution(&'a self) -> &'a RefCell> { self.name_resolutions.alloc(Default::default()) @@ -1406,7 +1406,7 @@ impl<'a> Resolver<'a> { misc2: AmbiguityErrorMisc::None, }); } - if let NameBindingKind::Import { directive, binding, ref used } = used_binding.kind { + if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind { // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. if is_lexical_scope { @@ -1419,17 +1419,17 @@ impl<'a> Resolver<'a> { } } used.set(true); - directive.used.set(true); - self.used_imports.insert((directive.id, ns)); - self.add_to_glob_map(&directive, ident); + import.used.set(true); + self.used_imports.insert((import.id, ns)); + self.add_to_glob_map(&import, ident); self.record_use(ident, ns, binding, false); } } #[inline] - fn add_to_glob_map(&mut self, directive: &Import<'_>, ident: Ident) { - if directive.is_glob() { - self.glob_map.entry(directive.id).or_default().insert(ident.name); + fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) { + if import.is_glob() { + self.glob_map.entry(import.id).or_default().insert(ident.name); } } @@ -2254,10 +2254,9 @@ impl<'a> Resolver<'a> { // `ExternCrate` (also used for `crate::...`) then no need to issue a // warning, this looks all good! if let Some(binding) = second_binding { - if let NameBindingKind::Import { directive: d, .. } = binding.kind { - // Careful: we still want to rewrite paths from - // renamed extern crates. - if let ImportKind::ExternCrate { source: None, .. } = d.kind { + if let NameBindingKind::Import { import, .. } = binding.kind { + // Careful: we still want to rewrite paths from renamed extern crates. + if let ImportKind::ExternCrate { source: None, .. } = import.kind { return; } } @@ -2560,10 +2559,10 @@ impl<'a> Resolver<'a> { // See https://github.com/rust-lang/rust/issues/32354 use NameBindingKind::Import; - let directive = match (&new_binding.kind, &old_binding.kind) { + let import = match (&new_binding.kind, &old_binding.kind) { // If there are two imports where one or both have attributes then prefer removing the // import without attributes. - (Import { directive: new, .. }, Import { directive: old, .. }) + (Import { import: new, .. }, Import { import: old, .. }) if { !new_binding.span.is_dummy() && !old_binding.span.is_dummy() @@ -2577,11 +2576,11 @@ impl<'a> Resolver<'a> { } } // Otherwise prioritize the new binding. - (Import { directive, .. }, other) if !new_binding.span.is_dummy() => { - Some((directive, new_binding.span, other.is_import())) + (Import { import, .. }, other) if !new_binding.span.is_dummy() => { + Some((import, new_binding.span, other.is_import())) } - (other, Import { directive, .. }) if !old_binding.span.is_dummy() => { - Some((directive, old_binding.span, other.is_import())) + (other, Import { import, .. }) if !old_binding.span.is_dummy() => { + Some((import, old_binding.span, other.is_import())) } _ => None, }; @@ -2598,22 +2597,22 @@ impl<'a> Resolver<'a> { && !has_dummy_span && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item); - match directive { - Some((directive, span, true)) if should_remove_import && directive.is_nested() => { - self.add_suggestion_for_duplicate_nested_use(&mut err, directive, span) + match import { + Some((import, span, true)) if should_remove_import && import.is_nested() => { + self.add_suggestion_for_duplicate_nested_use(&mut err, import, span) } - Some((directive, _, true)) if should_remove_import && !directive.is_glob() => { + Some((import, _, true)) if should_remove_import && !import.is_glob() => { // Simple case - remove the entire import. Due to the above match arm, this can // only be a single use so just remove it entirely. err.tool_only_span_suggestion( - directive.use_span_with_attributes, + import.use_span_with_attributes, "remove unnecessary import", String::new(), Applicability::MaybeIncorrect, ); } - Some((directive, span, _)) => { - self.add_suggestion_for_rename_of_use(&mut err, name, directive, span) + Some((import, span, _)) => { + self.add_suggestion_for_rename_of_use(&mut err, name, import, span) } _ => {} } @@ -2635,7 +2634,7 @@ impl<'a> Resolver<'a> { &self, err: &mut DiagnosticBuilder<'_>, name: Name, - directive: &Import<'_>, + import: &Import<'_>, binding_span: Span, ) { let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { @@ -2645,7 +2644,7 @@ impl<'a> Resolver<'a> { }; let mut suggestion = None; - match directive.kind { + match import.kind { ImportKind::Single { type_ns_only: true, .. } => { suggestion = Some(format!("self as {}", suggested_name)) } @@ -2707,27 +2706,27 @@ impl<'a> Resolver<'a> { /// If the nested use contains only one import then the suggestion will remove the entire /// line. /// - /// It is expected that the directive provided is a nested import - this isn't checked by the + /// It is expected that the provided import is nested - this isn't checked by the /// function. If this invariant is not upheld, this function's behaviour will be unexpected /// as characters expected by span manipulations won't be present. fn add_suggestion_for_duplicate_nested_use( &self, err: &mut DiagnosticBuilder<'_>, - directive: &Import<'_>, + import: &Import<'_>, binding_span: Span, ) { - assert!(directive.is_nested()); + assert!(import.is_nested()); let message = "remove unnecessary import"; // Two examples will be used to illustrate the span manipulations we're doing: // // - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is - // `a` and `directive.use_span` is `issue_52891::{d, a, e};`. + // `a` and `import.use_span` is `issue_52891::{d, a, e};`. // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is - // `a` and `directive.use_span` is `issue_52891::{d, e, a};`. + // `a` and `import.use_span` is `issue_52891::{d, e, a};`. let (found_closing_brace, span) = - find_span_of_binding_until_next_binding(self.session, binding_span, directive.use_span); + find_span_of_binding_until_next_binding(self.session, binding_span, import.use_span); // If there was a closing brace then identify the span to remove any trailing commas from // previous imports. @@ -2743,7 +2742,7 @@ impl<'a> Resolver<'a> { // Remove the entire line if we cannot extend the span back, this indicates a // `issue_52891::{self}` case. err.span_suggestion( - directive.use_span_with_attributes, + import.use_span_with_attributes, message, String::new(), Applicability::MaybeIncorrect, diff --git a/src/test/ui/rust-2018/macro-use-warned-against.rs b/src/test/ui/rust-2018/macro-use-warned-against.rs index 6cd54aa68aedd..65400163ddd86 100644 --- a/src/test/ui/rust-2018/macro-use-warned-against.rs +++ b/src/test/ui/rust-2018/macro-use-warned-against.rs @@ -4,7 +4,7 @@ #![warn(macro_use_extern_crate, unused)] -#[macro_use] //~ WARN should be replaced at use sites with a `use` statement +#[macro_use] //~ WARN should be replaced at use sites with a `use` item extern crate macro_use_warned_against; #[macro_use] //~ WARN unused `#[macro_use]` extern crate macro_use_warned_against2; diff --git a/src/test/ui/rust-2018/macro-use-warned-against.stderr b/src/test/ui/rust-2018/macro-use-warned-against.stderr index 611b9d5dac9fd..ef00b865815c0 100644 --- a/src/test/ui/rust-2018/macro-use-warned-against.stderr +++ b/src/test/ui/rust-2018/macro-use-warned-against.stderr @@ -1,4 +1,4 @@ -warning: deprecated `#[macro_use]` directive used to import macros should be replaced at use sites with a `use` statement to import the macro instead +warning: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead --> $DIR/macro-use-warned-against.rs:7:1 | LL | #[macro_use] From 2e88bec61916cdb5d24ee9c79af3f70f2d52cb5c Mon Sep 17 00:00:00 2001 From: Matthew Kuo Date: Sat, 7 Mar 2020 14:17:03 -0600 Subject: [PATCH 21/21] test(bindings_after_at): add dynamic drop tests for bindings_after_at --- src/test/ui/drop/dynamic-drop.rs | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index 451686d9ae21c..d31736f142c3f 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -3,6 +3,7 @@ #![feature(generators, generator_trait, untagged_unions)] #![feature(move_ref_pattern)] +#![feature(bindings_after_at)] #![allow(unused_assignments)] #![allow(unused_variables)] @@ -291,6 +292,44 @@ fn subslice_mixed_min_lengths(a: &Allocator, c: i32) { } } +fn bindings_after_at_dynamic_init_move(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + let _x; + + if let bar @ Some(_) = foo { + _x = bar; + } +} + +fn bindings_after_at_dynamic_init_ref(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + let _x; + + if let bar @ Some(_baz) = &foo { + _x = bar; + } +} + +fn bindings_after_at_dynamic_drop_move(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + + if let bar @ Some(_) = foo { + bar + } else { + None + }; +} + +fn bindings_after_at_dynamic_drop_ref(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + + if let bar @ Some(_baz) = &foo { + bar + } else { + &None + }; +} + fn move_ref_pattern(a: &Allocator) { let mut tup = (a.alloc(), a.alloc(), a.alloc(), a.alloc()); let (ref _a, ref mut _b, _c, mut _d) = tup; @@ -471,5 +510,14 @@ fn main() { run_test(|a| panic_after_init_temp(a)); run_test(|a| panic_after_init_by_loop(a)); + run_test(|a| bindings_after_at_dynamic_init_move(a, true)); + run_test(|a| bindings_after_at_dynamic_init_move(a, false)); + run_test(|a| bindings_after_at_dynamic_init_ref(a, true)); + run_test(|a| bindings_after_at_dynamic_init_ref(a, false)); + run_test(|a| bindings_after_at_dynamic_drop_move(a, true)); + run_test(|a| bindings_after_at_dynamic_drop_move(a, false)); + run_test(|a| bindings_after_at_dynamic_drop_ref(a, true)); + run_test(|a| bindings_after_at_dynamic_drop_ref(a, false)); + run_test_nopanic(|a| union1(a)); }