From 4ee18c94d4969a49b81b726260a093f3fd201070 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 Dec 2019 20:39:17 +0100 Subject: [PATCH 01/35] Clean up E0124 explanation --- src/librustc_error_codes/error_codes/E0124.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0124.md b/src/librustc_error_codes/error_codes/E0124.md index a7836526a7dd4..f08f7e9800551 100644 --- a/src/librustc_error_codes/error_codes/E0124.md +++ b/src/librustc_error_codes/error_codes/E0124.md @@ -1,5 +1,6 @@ -You declared two fields of a struct with the same name. Erroneous code -example: +A struct with two fields having the same name has been declared. + +Erroneous code example: ```compile_fail,E0124 struct Foo { From 1474d2a41a32f7f969c7d924ea917a1390ebe1c6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 Dec 2019 20:39:25 +0100 Subject: [PATCH 02/35] Clean up E0128 explanation --- src/librustc_error_codes/error_codes/E0128.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0128.md b/src/librustc_error_codes/error_codes/E0128.md index d0a4b32f9688e..6f8dfe3a73b9e 100644 --- a/src/librustc_error_codes/error_codes/E0128.md +++ b/src/librustc_error_codes/error_codes/E0128.md @@ -1,4 +1,5 @@ -Type parameter defaults can only use parameters that occur before them. +A type parameter with default value is using forward declared identifier. + Erroneous code example: ```compile_fail,E0128 @@ -7,11 +8,11 @@ struct Foo { field2: U, } // error: type parameters with a default cannot use forward declared -// identifiers +// identifiers ``` -Since type parameters are evaluated in-order, you may be able to fix this issue -by doing: +Type parameter defaults can only use parameters that occur before them. Since +type parameters are evaluated in-order, this issue could be fixed by doing: ``` struct Foo { From 101dd7bad9432730fa2f625ae43afcc2929457d4 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 23 Dec 2019 05:13:46 +0900 Subject: [PATCH 03/35] Use `is_none` instead of `if let` --- src/librustc/traits/error_reporting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b299fd6117e41..aabf1d625a8a8 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2289,7 +2289,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let span = self.tcx.def_span(generator_did); // Do not ICE on closure typeck (#66868). - if let None = self.tcx.hir().as_local_hir_id(generator_did) { + if self.tcx.hir().as_local_hir_id(generator_did).is_none() { return false; } From 7c485ccfad968ba6fe226a59f9337adbc158dd6b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 23 Dec 2019 07:35:18 +0900 Subject: [PATCH 04/35] Add test for issue-61747 --- src/test/ui/const-generics/issues/issue-61747.rs | 16 ++++++++++++++++ .../ui/const-generics/issues/issue-61747.stderr | 8 ++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-61747.rs create mode 100644 src/test/ui/const-generics/issues/issue-61747.stderr diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs new file mode 100644 index 0000000000000..cab87200b5022 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Const; + +impl Const<{C}> { + fn successor() -> Const<{C + 1}> { + Const + } +} + +fn main() { + Const::<1>::successor(); +} diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr new file mode 100644 index 0000000000000..ccf36a7f805ec --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61747.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61747.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + From 96253c2d15d5f9ed1e6e63a97ac5f705c8fc4421 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 23 Dec 2019 07:36:02 +0900 Subject: [PATCH 05/35] Add test for issue-66205 --- src/test/ui/const-generics/issues/issue-66205.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-66205.rs diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs new file mode 100644 index 0000000000000..2e47b4d1882f2 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -0,0 +1,10 @@ +// check-pass + +#![allow(incomplete_features, dead_code, unconditional_recursion)] +#![feature(const_generics)] + +fn fact() { + fact::<{ N - 1 }>(); +} + +fn main() {} From 6ec3a63bb287d11849b2fc3546793437bbbbd865 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 23 Dec 2019 07:36:30 +0900 Subject: [PATCH 06/35] Add test for issue-66270 --- .../issue-66270-pat-struct-parser-recovery.rs | 14 ++++++++++++++ .../issue-66270-pat-struct-parser-recovery.stderr | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs create mode 100644 src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs new file mode 100644 index 0000000000000..48a8e04829a0a --- /dev/null +++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs @@ -0,0 +1,14 @@ +// Regression test for #66270, fixed by #66246 + +struct Bug { + incorrect_field: 0, + //~^ ERROR expected type +} + +struct Empty {} + +fn main() { + let Bug { + any_field: Empty {}, + } = Bug {}; +} diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr new file mode 100644 index 0000000000000..fef0f3c0e06ef --- /dev/null +++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr @@ -0,0 +1,8 @@ +error: expected type, found `0` + --> $DIR/issue-66270-pat-struct-parser-recovery.rs:4:22 + | +LL | incorrect_field: 0, + | ^ expected type + +error: aborting due to previous error + From 256eec4ae0653e35cdd39261a2b59d69c91b1a71 Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Mon, 23 Dec 2019 12:55:33 +0530 Subject: [PATCH 07/35] Update E0124.md --- src/librustc_error_codes/error_codes/E0124.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0124.md b/src/librustc_error_codes/error_codes/E0124.md index f08f7e9800551..8af7cb819cfaf 100644 --- a/src/librustc_error_codes/error_codes/E0124.md +++ b/src/librustc_error_codes/error_codes/E0124.md @@ -1,4 +1,4 @@ -A struct with two fields having the same name has been declared. +A struct was declared with two fields having the same name. Erroneous code example: From 1485c168990b2dbb6e2858bc09af0254c1af9491 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Mon, 23 Dec 2019 21:05:02 +0800 Subject: [PATCH 08/35] Add long error code explanation message for E0627 --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_error_codes/error_codes/E0627.md | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/librustc_error_codes/error_codes/E0627.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 9c1bec39b29e2..fbcc976bd491e 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -346,6 +346,7 @@ E0622: include_str!("./error_codes/E0622.md"), E0623: include_str!("./error_codes/E0623.md"), E0624: include_str!("./error_codes/E0624.md"), E0626: include_str!("./error_codes/E0626.md"), +E0627: include_str!("./error_codes/E0627.md"), E0631: include_str!("./error_codes/E0631.md"), E0633: include_str!("./error_codes/E0633.md"), E0635: include_str!("./error_codes/E0635.md"), @@ -574,7 +575,6 @@ E0745: include_str!("./error_codes/E0745.md"), // E0612, // merged into E0609 // E0613, // Removed (merged with E0609) E0625, // thread-local statics cannot be accessed at compile-time - E0627, // yield statement outside of generator literal E0628, // generators cannot have explicit parameters E0629, // missing 'feature' (rustc_const_unstable) // rustc_const_unstable attribute must be paired with stable/unstable diff --git a/src/librustc_error_codes/error_codes/E0627.md b/src/librustc_error_codes/error_codes/E0627.md new file mode 100644 index 0000000000000..21358e1e567dc --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0627.md @@ -0,0 +1,30 @@ +A yield expression was used outside of the generator literal. + +Erroneous code example: + +```compile_fail,E0627 +#![feature(generators, generator_trait)] + +fn fake_generator() -> &'static str { + yield 1; + return "foo" +} + +fn main() { + let mut generator = fake_generator; +} +``` + +The error occurs because keyword `yield` can only be used inside the generator +literal. This can be fixed by constructing the generator correctly. + +``` +#![feature(generators, generator_trait)] + +fn main() { + let mut generator = || { + yield 1; + return "foo" + }; +} +``` From 587d03bea89b2b551633aa561073ba97409a5dac Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Mon, 23 Dec 2019 21:07:13 +0800 Subject: [PATCH 09/35] Yield is an expression form, not a statement. --- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/borrow_check/path_utils.rs | 2 +- src/librustc_typeck/check/expr.rs | 2 +- src/test/ui/feature-gates/feature-gate-generators.rs | 2 +- src/test/ui/feature-gates/feature-gate-generators.stderr | 5 +++-- src/test/ui/generator/yield-in-const.rs | 2 +- src/test/ui/generator/yield-in-const.stderr | 3 ++- src/test/ui/generator/yield-in-function.rs | 2 +- src/test/ui/generator/yield-in-function.stderr | 3 ++- src/test/ui/generator/yield-in-static.rs | 2 +- src/test/ui/generator/yield-in-static.stderr | 3 ++- 11 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4a6379e3bc155..0d136bd7d9cf9 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1424,7 +1424,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// Reports an error if this is a borrow of local data. - /// This is called for all Yield statements on movable generators + /// This is called for all Yield expressions on movable generators fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) { debug!("check_for_local_borrow({:?})", borrow); diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index ea541bd93bc94..23b4799643a6c 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -131,7 +131,7 @@ pub(super) fn is_active<'tcx>( } /// Determines if a given borrow is borrowing local data -/// This is called for all Yield statements on movable generators +/// This is called for all Yield expressions on movable generators pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool { match place.base { PlaceBase::Static(_) => false, diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 6ecf3ccd6e7ed..479536a1c8f01 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1775,7 +1775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess, expr.span, E0627, - "yield statement outside of generator literal" + "yield expression outside of generator literal" ) .emit(); } diff --git a/src/test/ui/feature-gates/feature-gate-generators.rs b/src/test/ui/feature-gates/feature-gate-generators.rs index 382d891feed84..931fee1347126 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.rs +++ b/src/test/ui/feature-gates/feature-gate-generators.rs @@ -1,6 +1,6 @@ fn main() { yield true; //~ ERROR yield syntax is experimental - //~^ ERROR yield statement outside of generator literal + //~^ ERROR yield expression outside of generator literal } #[cfg(FALSE)] diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr index 24b814b410c9d..4adc21efc6a21 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.stderr +++ b/src/test/ui/feature-gates/feature-gate-generators.stderr @@ -25,7 +25,7 @@ LL | yield 0; = note: for more information, see https://github.com/rust-lang/rust/issues/43122 = help: add `#![feature(generators)]` to the crate attributes to enable -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/feature-gate-generators.rs:2:5 | LL | yield true; @@ -33,4 +33,5 @@ LL | yield true; error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0627, E0658. +For more information about an error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-const.rs b/src/test/ui/generator/yield-in-const.rs index f6f11b9cb13dd..fe5ca822ceca1 100644 --- a/src/test/ui/generator/yield-in-const.rs +++ b/src/test/ui/generator/yield-in-const.rs @@ -1,6 +1,6 @@ #![feature(generators)] const A: u8 = { yield 3u8; 3u8}; -//~^ ERROR yield statement outside +//~^ ERROR yield expression outside fn main() {} diff --git a/src/test/ui/generator/yield-in-const.stderr b/src/test/ui/generator/yield-in-const.stderr index 663bb70d7a07f..dcf4fe63e64bc 100644 --- a/src/test/ui/generator/yield-in-const.stderr +++ b/src/test/ui/generator/yield-in-const.stderr @@ -1,4 +1,4 @@ -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/yield-in-const.rs:3:17 | LL | const A: u8 = { yield 3u8; 3u8}; @@ -6,3 +6,4 @@ LL | const A: u8 = { yield 3u8; 3u8}; error: aborting due to previous error +For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-function.rs b/src/test/ui/generator/yield-in-function.rs index b737d3b224035..29b811621de1e 100644 --- a/src/test/ui/generator/yield-in-function.rs +++ b/src/test/ui/generator/yield-in-function.rs @@ -1,4 +1,4 @@ #![feature(generators)] fn main() { yield; } -//~^ ERROR yield statement outside +//~^ ERROR yield expression outside diff --git a/src/test/ui/generator/yield-in-function.stderr b/src/test/ui/generator/yield-in-function.stderr index e12b0e6843e41..51cce198ca3b4 100644 --- a/src/test/ui/generator/yield-in-function.stderr +++ b/src/test/ui/generator/yield-in-function.stderr @@ -1,4 +1,4 @@ -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/yield-in-function.rs:3:13 | LL | fn main() { yield; } @@ -6,3 +6,4 @@ LL | fn main() { yield; } error: aborting due to previous error +For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-static.rs b/src/test/ui/generator/yield-in-static.rs index 12c9ccea4cb78..d27fbb33ba10a 100644 --- a/src/test/ui/generator/yield-in-static.rs +++ b/src/test/ui/generator/yield-in-static.rs @@ -1,6 +1,6 @@ #![feature(generators)] static B: u8 = { yield 3u8; 3u8}; -//~^ ERROR yield statement outside +//~^ ERROR yield expression outside fn main() {} diff --git a/src/test/ui/generator/yield-in-static.stderr b/src/test/ui/generator/yield-in-static.stderr index 220520c3862ca..d867f3ad34528 100644 --- a/src/test/ui/generator/yield-in-static.stderr +++ b/src/test/ui/generator/yield-in-static.stderr @@ -1,4 +1,4 @@ -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/yield-in-static.rs:3:18 | LL | static B: u8 = { yield 3u8; 3u8}; @@ -6,3 +6,4 @@ LL | static B: u8 = { yield 3u8; 3u8}; error: aborting due to previous error +For more information about this error, try `rustc --explain E0627`. From 24f3dcfdc741aaab0f1e56127455143912bc9203 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 23 Dec 2019 09:47:28 -0600 Subject: [PATCH 10/35] remove `description` from `Error` impls in docs --- src/libstd/error.rs | 32 ++++---------------------------- src/libstd/io/error.rs | 4 +--- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index d4c4cb9c3b997..f62c05c444115 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -91,10 +91,6 @@ pub trait Error: Debug + Display { /// } /// /// impl Error for SuperError { - /// fn description(&self) -> &str { - /// "I'm the superhero of errors" - /// } - /// /// fn cause(&self) -> Option<&dyn Error> { /// Some(&self.side) /// } @@ -109,11 +105,7 @@ pub trait Error: Debug + Display { /// } /// } /// - /// impl Error for SuperErrorSideKick { - /// fn description(&self) -> &str { - /// "I'm SuperError side kick" - /// } - /// } + /// impl Error for SuperErrorSideKick {} /// /// fn get_super_error() -> Result<(), SuperError> { /// Err(SuperError { side: SuperErrorSideKick }) @@ -156,10 +148,6 @@ pub trait Error: Debug + Display { /// } /// /// impl Error for SuperError { - /// fn description(&self) -> &str { - /// "I'm the superhero of errors" - /// } - /// /// fn source(&self) -> Option<&(dyn Error + 'static)> { /// Some(&self.side) /// } @@ -174,11 +162,7 @@ pub trait Error: Debug + Display { /// } /// } /// - /// impl Error for SuperErrorSideKick { - /// fn description(&self) -> &str { - /// "I'm SuperError side kick" - /// } - /// } + /// impl Error for SuperErrorSideKick {} /// /// fn get_super_error() -> Result<(), SuperError> { /// Err(SuperError { side: SuperErrorSideKick }) @@ -251,11 +235,7 @@ impl<'a, E: Error + 'a> From for Box { /// } /// } /// - /// impl Error for AnError { - /// fn description(&self) -> &str { - /// "Description of an error" - /// } - /// } + /// impl Error for AnError {} /// /// let an_error = AnError; /// assert!(0 == mem::size_of_val(&an_error)); @@ -290,11 +270,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box &str { - /// "Description of an error" - /// } - /// } + /// impl Error for AnError {} /// /// unsafe impl Send for AnError {} /// diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index c20bd3097b27d..efe839d1302fe 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -402,9 +402,7 @@ impl Error { /// } /// } /// - /// impl error::Error for MyError { - /// fn description(&self) -> &str { &self.v } - /// } + /// impl error::Error for MyError {} /// /// impl Display for MyError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 1f2fa939a5536eeff86c0ea6b7ebde538a582ad4 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 23 Dec 2019 07:37:16 +0900 Subject: [PATCH 11/35] Add test for issue-67424 --- .../generic-associated-types/issue-67424.rs | 13 ++++++++++++ .../issue-67424.stderr | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/ui/generic-associated-types/issue-67424.rs create mode 100644 src/test/ui/generic-associated-types/issue-67424.stderr diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs new file mode 100644 index 0000000000000..9b616b8abc2ee --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67424.rs @@ -0,0 +1,13 @@ +// Fixed by #67160 + +trait Trait1 { + type A; +} + +trait Trait2 { + type Type1: Trait1; + //~^ ERROR: generic associated types are unstable + //~| ERROR: type-generic associated types are not yet implemented +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr new file mode 100644 index 0000000000000..59ff8ac0a3a70 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67424.stderr @@ -0,0 +1,20 @@ +error[E0658]: generic associated types are unstable + --> $DIR/issue-67424.rs:8:5 + | +LL | type Type1: Trait1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 + = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable + +error: type-generic associated types are not yet implemented + --> $DIR/issue-67424.rs:8:5 + | +LL | type Type1: Trait1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From d918319bed23b418a98720688a3f59904aada978 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 23 Dec 2019 08:24:11 +0900 Subject: [PATCH 12/35] Apply suggestion from Centril Co-Authored-By: Mazdak Farrokhzad --- src/test/ui/const-generics/issues/issue-61747.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index cab87200b5022..64674bb894e1f 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -12,5 +12,5 @@ impl Const<{C}> { } fn main() { - Const::<1>::successor(); + let _x: Const::<2> = Const::<1>::successor(); } From 2536c75d4fff3b86087c3ffd9ea7540ce99ae2fd Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Dec 2019 00:01:12 +0100 Subject: [PATCH 13/35] Don't ICE on the use of integer addresses for ZST constants in pattern matching --- src/librustc/mir/interpret/allocation.rs | 4 ++ src/librustc_mir/hair/pattern/_match.rs | 52 ++++++++++++++++++------ src/librustc_mir/hair/pattern/mod.rs | 6 +++ src/test/ui/consts/consts-in-patterns.rs | 13 ++++++ 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 67f1c8072d680..957a028a59ebb 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -127,6 +127,10 @@ impl Allocation { extra: (), } } + + pub fn zst(align: Align) -> Self { + Self::undef(Size::ZERO, align) + } } impl Allocation<(), ()> { diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index f267be812c3d2..9851f24689744 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -237,11 +237,11 @@ use super::{FieldPat, Pat, PatKind, PatRange}; use rustc::hir::def_id::DefId; use rustc::hir::{HirId, RangeEnd}; -use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx}; +use rustc::ty::layout::{Align, Integer, IntegerExt, Size, VariantIdx}; use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef}; use rustc::lint; -use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; +use rustc::mir::interpret::{truncate, AllocId, Allocation, ConstValue, Pointer, Scalar}; use rustc::mir::Field; use rustc::util::captures::Captures; use rustc::util::common::ErrorReported; @@ -252,6 +252,7 @@ use syntax_pos::{Span, DUMMY_SP}; use arena::TypedArena; use smallvec::{smallvec, SmallVec}; +use std::borrow::Cow; use std::cmp::{self, max, min, Ordering}; use std::convert::TryInto; use std::fmt; @@ -260,11 +261,12 @@ use std::ops::RangeInclusive; use std::u128; pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> { - LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat) + LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat) } struct LiteralExpander<'tcx> { tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, } impl LiteralExpander<'tcx> { @@ -284,9 +286,23 @@ impl LiteralExpander<'tcx> { debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty); match (val, &crty.kind, &rty.kind) { // the easy case, deref a reference - (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => { - let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); - ConstValue::ByRef { alloc, offset: p.offset } + (ConstValue::Scalar(p), x, y) if x == y => { + match p { + Scalar::Ptr(p) => { + let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); + ConstValue::ByRef { alloc, offset: p.offset } + } + Scalar::Raw { .. } => { + let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap(); + if layout.is_zst() { + // Deref of a reference to a ZST is a nop. + ConstValue::Scalar(Scalar::zst()) + } else { + // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` + bug!("cannot deref {:#?}, {} -> {}", val, crty, rty); + } + } + } } // unsize array to slice if pattern is array but match value or other patterns are slice (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { @@ -2348,16 +2364,28 @@ fn specialize_one_pattern<'p, 'tcx>( // just integers. The only time they should be pointing to memory // is when they are subslices of nonzero slices. let (alloc, offset, n, ty) = match value.ty.kind { - ty::Array(t, n) => match value.val { - ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => { - (alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t) + ty::Array(t, n) => { + let n = n.eval_usize(cx.tcx, cx.param_env); + match value.val { + ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => { + (Cow::Borrowed(alloc), offset, n, t) + } + ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })) + if n == 0 => + { + let align = Align::from_bytes(data as u64).unwrap(); + // empty array + (Cow::Owned(Allocation::zst(align)), Size::ZERO, 0, t) + } + _ => span_bug!(pat.span, "array pattern is {:?}", value,), } - _ => span_bug!(pat.span, "array pattern is {:?}", value,), - }, + } ty::Slice(t) => { match value.val { ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => { - (data, Size::from_bytes(start as u64), (end - start) as u64, t) + let offset = Size::from_bytes(start as u64); + let n = (end - start) as u64; + (Cow::Borrowed(data), offset, n, t) } ty::ConstKind::Value(ConstValue::ByRef { .. }) => { // FIXME(oli-obk): implement `deref` for `ConstValue` diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 869aeeba418da..a68ee3308bc23 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -993,6 +993,12 @@ pub fn compare_const_vals<'tcx>( return fallback(); } + // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they + // are just integer addresses). + if a.val == b.val { + return from_bool(true); + } + let a_bits = a.try_eval_bits(tcx, param_env, ty); let b_bits = b.try_eval_bits(tcx, param_env, ty); diff --git a/src/test/ui/consts/consts-in-patterns.rs b/src/test/ui/consts/consts-in-patterns.rs index ac6c5a5150688..ee1e3cc22f77d 100644 --- a/src/test/ui/consts/consts-in-patterns.rs +++ b/src/test/ui/consts/consts-in-patterns.rs @@ -1,7 +1,10 @@ // run-pass +#![feature(const_transmute)] const FOO: isize = 10; const BAR: isize = 3; +const ZST: &() = unsafe { std::mem::transmute(1usize) }; +const ZST_ARR: &[u8; 0] = unsafe { std::mem::transmute(1usize) }; const fn foo() -> isize { 4 } const BOO: isize = foo(); @@ -15,4 +18,14 @@ pub fn main() { _ => 3 }; assert_eq!(y, 2); + let z = match &() { + ZST => 9, + // FIXME: this should not be required + _ => 42, + }; + assert_eq!(z, 9); + let z = match b"" { + ZST_ARR => 10, + }; + assert_eq!(z, 10); } From cc5cc6744b5ae5a5ee6db0db80448aa12a5d45f6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Dec 2019 00:04:27 +0100 Subject: [PATCH 14/35] Retire `to_ptr` which should already have no users but still kept getting new ones --- src/librustc/mir/interpret/value.rs | 9 ++------- src/librustc/ty/relate.rs | 4 ++-- src/librustc_mir/const_eval.rs | 6 +++--- src/librustc_mir/interpret/eval_context.rs | 4 +++- src/librustc_mir/interpret/intern.rs | 15 +++++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 49b542af0a034..93f167cdb9e54 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -367,8 +367,9 @@ impl<'tcx, Tag> Scalar { } /// Do not call this method! Use either `assert_ptr` or `force_ptr`. + /// This method is intentionally private, do not make it public. #[inline] - pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { + fn to_ptr(self) -> InterpResult<'tcx, Pointer> { match self { Scalar::Raw { data: 0, .. } => throw_unsup!(InvalidNullPointerUsage), Scalar::Raw { .. } => throw_unsup!(ReadBytesAsPointer), @@ -544,12 +545,6 @@ impl<'tcx, Tag> ScalarMaybeUndef { } } - /// Do not call this method! Use either `assert_ptr` or `force_ptr`. - #[inline(always)] - pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { - self.not_undef()?.to_ptr() - } - /// Do not call this method! Use either `assert_bits` or `force_bits`. #[inline(always)] pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 933358dce018b..120f05ba7d974 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -537,8 +537,8 @@ pub fn super_relate_consts>( Ok(ConstValue::Scalar(a_val)) } else if let ty::FnPtr(_) = a.ty.kind { let alloc_map = tcx.alloc_map.lock(); - let a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id); - let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id); + let a_instance = alloc_map.unwrap_fn(a_val.assert_ptr().alloc_id); + let b_instance = alloc_map.unwrap_fn(b_val.assert_ptr().alloc_id); if a_instance == b_instance { Ok(ConstValue::Scalar(a_val)) } else { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index a2f066bee08d1..2afa39c3cad8b 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -85,7 +85,7 @@ fn op_to_const<'tcx>( }; let val = match immediate { Ok(mplace) => { - let ptr = mplace.ptr.to_ptr().unwrap(); + let ptr = mplace.ptr.assert_ptr(); let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); ConstValue::ByRef { alloc, offset: ptr.offset } }, @@ -99,7 +99,7 @@ fn op_to_const<'tcx>( // comes from a constant so it can happen have `Undef`, because the indirect // memory that was read had undefined bytes. let mplace = op.assert_mem_place(); - let ptr = mplace.ptr.to_ptr().unwrap(); + let ptr = mplace.ptr.assert_ptr(); let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); ConstValue::ByRef { alloc, offset: ptr.offset } }, @@ -626,7 +626,7 @@ fn validate_and_turn_into_const<'tcx>( // whether they become immediates. let def_id = cid.instance.def.def_id(); if tcx.is_static(def_id) || cid.promoted.is_some() { - let ptr = mplace.ptr.to_ptr()?; + let ptr = mplace.ptr.assert_ptr(); Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(ConstValue::ByRef { alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index ad2af8d7aca52..e8576b198dc24 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -743,7 +743,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME: should we tell the user that there was a local which was never written to? if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { trace!("deallocating local"); - let ptr = ptr.to_ptr()?; + // All locals have a backing allocation, even if the allocation is empty + // due to the local having ZST type. + let ptr = ptr.assert_ptr(); if log_enabled!(::log::Level::Trace) { self.memory.dump_alloc(ptr.alloc_id); } diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index c99f39977fe2e..d02f3df03a5ca 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -192,11 +192,12 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx if let ty::Dynamic(..) = self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind { - if let Ok(vtable) = mplace.meta.unwrap().to_ptr() { - // explitly choose `Immutable` here, since vtables are immutable, even - // if the reference of the fat pointer is mutable - self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; - } + // Validation has already errored on an invalid vtable pointer so this `assert_ptr` + // will never panic. + let vtable = mplace.meta.unwrap().assert_ptr(); + // explitly choose `Immutable` here, since vtables are immutable, even + // if the reference of the fat pointer is mutable + self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; } // Check if we have encountered this pointer+layout combination before. // Only recurse for allocation-backed pointers. @@ -281,7 +282,9 @@ pub fn intern_const_alloc_recursive>( ecx, leftover_allocations, base_intern_mode, - ret.ptr.to_ptr()?.alloc_id, + // The outermost allocation must exist, because we allocated it with + // `Memory::allocate`. + ret.ptr.assert_ptr().alloc_id, base_mutability, Some(ret.layout.ty), )?; From 8be7c5415356f4941efa4d816456464080f292ef Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Dec 2019 00:05:04 +0100 Subject: [PATCH 15/35] Simplify `force_allocation_maybe_sized` --- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/interpret/place.rs | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e8576b198dc24..5ba9dcd3aa5c8 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -118,7 +118,7 @@ pub struct LocalState<'tcx, Tag = (), Id = AllocId> { } /// Current value of a local variable -#[derive(Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these +#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these pub enum LocalValue { /// This local is not currently alive, and cannot be used at all. Dead, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index a1e6eb69b9d0d..8ff218a056ab8 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -986,30 +986,20 @@ where let (mplace, size) = match place.place { Place::Local { frame, local } => { match self.stack[frame].locals[local].access_mut()? { - Ok(local_val) => { + Ok(&mut local_val) => { // We need to make an allocation. - // FIXME: Consider not doing anything for a ZST, and just returning - // a fake pointer? Are we even called for ZST? - - // We cannot hold on to the reference `local_val` while allocating, - // but we can hold on to the value in there. - let old_val = - if let LocalValue::Live(Operand::Immediate(value)) = *local_val { - Some(value) - } else { - None - }; // We need the layout of the local. We can NOT use the layout we got, // that might e.g., be an inner field of a struct with `Scalar` layout, // that has different alignment than the outer field. - // We also need to support unsized types, and hence cannot use `allocate`. let local_layout = self.layout_of_local(&self.stack[frame], local, None)?; + + // We also need to support unsized types, and hence cannot use `allocate`. let (size, align) = self.size_and_align_of(meta, local_layout)? .expect("Cannot allocate for non-dyn-sized type"); let ptr = self.memory.allocate(size, align, MemoryKind::Stack); let mplace = MemPlace { ptr: ptr.into(), align, meta }; - if let Some(value) = old_val { + if let LocalValue::Live(Operand::Immediate(value)) = local_val { // Preserve old value. // We don't have to validate as we can assume the local // was already valid for its type. From 53ca7383cc4ec37ebeca4e35ae6c595e80a0bfe9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Dec 2019 00:05:28 +0100 Subject: [PATCH 16/35] Comment on a few odd things that we should look at --- src/librustc_mir/interpret/eval_context.rs | 2 ++ src/librustc_mir/interpret/operand.rs | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 5ba9dcd3aa5c8..7a26857c560e0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -761,6 +761,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME(oli-obk): make this check an assertion that it's not a static here // FIXME(RalfJ, oli-obk): document that `Place::Static` can never be anything but a static // and `ConstValue::Unevaluated` can never be a static + // FIXME(oli-obk, spastorino): the above FIXME is not true anymore, PlaceBase::Static does + // not exist anymore (except for promoteds but it's going away soon). let param_env = if self.tcx.is_static(gid.instance.def_id()) { ty::ParamEnv::reveal_all() } else { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index a89abe71c654f..82974f338d2ab 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -578,13 +578,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), ty::ConstKind::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; + // FIXME: don't use `const_eval_raw` for regular constants, instead use `const_eval` + // which immediately validates the result before we continue with it here. return Ok(OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None })?)); } - ty::ConstKind::Infer(..) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) => { - bug!("eval_const_to_op: Unexpected ConstKind {:?}", val) - } ty::ConstKind::Value(val_val) => val_val, }; // Other cases need layout. From 6976435755abe87fac8aa5f2e44eed7c40b611fa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Dec 2019 00:19:24 +0100 Subject: [PATCH 17/35] Prevent an ICE on invalid transmutes --- src/librustc/mir/interpret/error.rs | 6 + src/librustc_mir/interpret/place.rs | 6 +- .../transmute-size-mismatch-before-typeck.rs | 15 ++ ...ansmute-size-mismatch-before-typeck.stderr | 136 ++++++++++++++++++ 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/consts/transmute-size-mismatch-before-typeck.rs create mode 100644 src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 843880200f3d7..51f0818fe0be1 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -432,6 +432,7 @@ pub enum UnsupportedOpInfo<'tcx> { HeapAllocNonPowerOfTwoAlignment(u64), ReadFromReturnPointer, PathNotFound(Vec), + TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), } impl fmt::Debug for UnsupportedOpInfo<'tcx> { @@ -460,6 +461,11 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { passing data of type {:?}", callee_ty, caller_ty ), + TransmuteSizeDiff(from_ty, to_ty) => write!( + f, + "tried to transmute from {:?} to {:?}, but their sizes differed", + from_ty, to_ty + ), FunctionRetMismatch(caller_ty, callee_ty) => write!( f, "tried to call a function with return type {:?} \ diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 8ff218a056ab8..bf9486c2ed2b7 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -941,8 +941,10 @@ where return self.copy_op(src, dest); } // We still require the sizes to match. - assert!(src.layout.size == dest.layout.size, - "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + if src.layout.size != dest.layout.size { + error!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + throw_unsup!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); + } // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want // to avoid that here. assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs new file mode 100644 index 0000000000000..1235dd8dcbd98 --- /dev/null +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -0,0 +1,15 @@ +#![feature(const_transmute)] + +fn main() { + match &b""[..] { + ZST => {} + //~^ ERROR could not evaluate constant pattern + } +} + +const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; +//~^ ERROR any use of this value will cause an error +//~| ERROR cannot transmute between types of different sizes + +// Once the `any use of this value will cause an error` disappears in this test, make sure to +// remove the `TransmuteSizeDiff` error variant and make its emitter site an assertion again. diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr new file mode 100644 index 0000000000000..29aeb42898739 --- /dev/null +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -0,0 +1,136 @@ +[ERROR rustc_mir::interpret::place] Size mismatch when transmuting! + src: OpTy { + op: Immediate( + Scalar( + 0x0000000000000001, + ), + ), + layout: TyLayout { + ty: usize, + details: LayoutDetails { + variants: Single { + index: 0, + }, + fields: Union( + 0, + ), + abi: Scalar( + Scalar { + value: Int( + I64, + false, + ), + valid_range: 0..=18446744073709551615, + }, + ), + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align { + pow2: 3, + }, + pref: Align { + pow2: 3, + }, + }, + size: Size { + raw: 8, + }, + }, + }, + } + dest: PlaceTy { + place: Ptr( + MemPlace { + ptr: AllocId(0).0x0, + align: Align { + pow2: 3, + }, + meta: None, + }, + ), + layout: TyLayout { + ty: &[u8], + details: LayoutDetails { + variants: Single { + index: 0, + }, + fields: Arbitrary { + offsets: [ + Size { + raw: 0, + }, + Size { + raw: 8, + }, + ], + memory_index: [ + 0, + 1, + ], + }, + abi: ScalarPair( + Scalar { + value: Pointer, + valid_range: 1..=18446744073709551615, + }, + Scalar { + value: Int( + I64, + false, + ), + valid_range: 0..=18446744073709551615, + }, + ), + largest_niche: Some( + Niche { + offset: Size { + raw: 0, + }, + scalar: Scalar { + value: Pointer, + valid_range: 1..=18446744073709551615, + }, + }, + ), + align: AbiAndPrefAlign { + abi: Align { + pow2: 3, + }, + pref: Align { + pow2: 3, + }, + }, + size: Size { + raw: 16, + }, + }, + }, + } +error: any use of this value will cause an error + --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | tried to transmute from usize to &[u8], but their sizes differed + | + = note: `#[deny(const_err)]` on by default + +error: could not evaluate constant pattern + --> $DIR/transmute-size-mismatch-before-typeck.rs:5:9 + | +LL | ZST => {} + | ^^^ + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `usize` (64 bits) + = note: target type: `&'static [u8]` (128 bits) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0512`. From 68ecc2165a5065871929cb680cad90af55958c8b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Dec 2019 12:15:37 +0100 Subject: [PATCH 18/35] Interning even happens when validation of a constant fails --- src/librustc_mir/interpret/intern.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index d02f3df03a5ca..ee082c34b6ab9 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -192,12 +192,18 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx if let ty::Dynamic(..) = self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind { - // Validation has already errored on an invalid vtable pointer so this `assert_ptr` - // will never panic. - let vtable = mplace.meta.unwrap().assert_ptr(); - // explitly choose `Immutable` here, since vtables are immutable, even - // if the reference of the fat pointer is mutable - self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; + // Validation has already errored on an invalid vtable pointer so we can safely not + // do anything if this is not a real pointer + if let Scalar::Ptr(vtable) = mplace.meta.unwrap() { + // explitly choose `Immutable` here, since vtables are immutable, even + // if the reference of the fat pointer is mutable + self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; + } else { + self.ecx().tcx.sess.delay_span_bug( + syntax_pos::DUMMY_SP, + "vtables pointers cannot be integer pointers", + ); + } } // Check if we have encountered this pointer+layout combination before. // Only recurse for allocation-backed pointers. From c4f9215f0f32100a358307b77e6c374b0ab0eca2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 20 Dec 2019 12:31:52 +0100 Subject: [PATCH 19/35] Immediately evaluate and validate constants when we want them as operands --- src/librustc_mir/interpret/operand.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 82974f338d2ab..110dadbfb378f 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -578,9 +578,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), ty::ConstKind::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; - // FIXME: don't use `const_eval_raw` for regular constants, instead use `const_eval` - // which immediately validates the result before we continue with it here. - return Ok(OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None })?)); + let param_env = if self.tcx.is_static(def_id) { + ty::ParamEnv::reveal_all() + } else { + self.param_env + }; + let val = + self.tcx.const_eval(param_env.and(GlobalId { instance, promoted: None }))?; + // "recurse". This is only ever going into a recusion depth of 1, because after + // `const_eval` we don't have `Unevaluated` anymore. + return self.eval_const_to_op(val, layout); } ty::ConstKind::Value(val_val) => val_val, }; From 7ef8cf4ae5e3195d55d84f3f17859f5a78fdad50 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 20 Dec 2019 12:37:05 +0100 Subject: [PATCH 20/35] Add regression test for ZST statics being allowed to "read" from themselves --- src/test/ui/consts/recursive-zst-static.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/test/ui/consts/recursive-zst-static.rs diff --git a/src/test/ui/consts/recursive-zst-static.rs b/src/test/ui/consts/recursive-zst-static.rs new file mode 100644 index 0000000000000..df7562bd9f5d2 --- /dev/null +++ b/src/test/ui/consts/recursive-zst-static.rs @@ -0,0 +1,7 @@ +// build-pass + +static FOO: () = FOO; + +fn main() { + FOO +} From 58eec1757075a4707d6e4fdbc1d6741069849273 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 12:54:48 +0100 Subject: [PATCH 21/35] Explain ParamEnv::reveal_all usage --- src/librustc_mir/interpret/operand.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 110dadbfb378f..78638a399482b 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -578,6 +578,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), ty::ConstKind::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; + // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics + // and thus don't care about the parameter environment. While we could just use + // `self.param_env`, that would mean we invoke the query to evaluate the static + // with different parameter environments, thus causing the static to be evaluated + // multiple times. let param_env = if self.tcx.is_static(def_id) { ty::ParamEnv::reveal_all() } else { From 51937efdbe7f4511e3ae13dfae38f1ec12372dfa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 12:55:31 +0100 Subject: [PATCH 22/35] Comments should start capitalized and end in a period --- src/librustc_mir/interpret/intern.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index ee082c34b6ab9..7463aaf509860 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -188,15 +188,15 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx if let ty::Ref(_, referenced_ty, mutability) = ty.kind { let value = self.ecx.read_immediate(mplace.into())?; let mplace = self.ecx.ref_to_mplace(value)?; - // Handle trait object vtables + // Handle trait object vtables. if let ty::Dynamic(..) = self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind { // Validation has already errored on an invalid vtable pointer so we can safely not - // do anything if this is not a real pointer + // do anything if this is not a real pointer. if let Scalar::Ptr(vtable) = mplace.meta.unwrap() { - // explitly choose `Immutable` here, since vtables are immutable, even - // if the reference of the fat pointer is mutable + // Explitly choose `Immutable` here, since vtables are immutable, even + // if the reference of the fat pointer is mutable. self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; } else { self.ecx().tcx.sess.delay_span_bug( From 5b278bc55028b36eef913d36ce96ee29378ee7f0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 12:59:15 +0100 Subject: [PATCH 23/35] Explain what we are doing with parameter environments for statics --- src/librustc_mir/interpret/eval_context.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 7a26857c560e0..76f74a3ecaa69 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -758,11 +758,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // FIXME(oli-obk): make this check an assertion that it's not a static here - // FIXME(RalfJ, oli-obk): document that `Place::Static` can never be anything but a static - // and `ConstValue::Unevaluated` can never be a static - // FIXME(oli-obk, spastorino): the above FIXME is not true anymore, PlaceBase::Static does - // not exist anymore (except for promoteds but it's going away soon). + // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics + // and thus don't care about the parameter environment. While we could just use + // `self.param_env`, that would mean we invoke the query to evaluate the static + // with different parameter environments, thus causing the static to be evaluated + // multiple times. let param_env = if self.tcx.is_static(gid.instance.def_id()) { ty::ParamEnv::reveal_all() } else { From efbbc6985a43420133fae300aef2c9f1395dd1ff Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 13:06:50 +0100 Subject: [PATCH 24/35] Explain the currently necessary existance of `TransmuteSizeDiff` --- src/librustc_mir/interpret/place.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index bf9486c2ed2b7..36b64756da34e 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -942,6 +942,10 @@ where } // We still require the sizes to match. if src.layout.size != dest.layout.size { + // FIXME: This should be an assert instead of an error, but if we transmute within an + // array length computation, `typeck` may not have yet been run and errored out. In fact + // most likey we *are* running `typeck` right now. Investigate whether we can bail out + // on `typeck_tables().has_errors` at all const eval entry points. error!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); throw_unsup!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); } From 405dbc6267147bfe0866c3700f7c7f2e368abb1b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 13:10:56 +0100 Subject: [PATCH 25/35] Remove unintended noisy log statement --- src/librustc_mir/interpret/place.rs | 2 +- ...ansmute-size-mismatch-before-typeck.stderr | 108 ------------------ 2 files changed, 1 insertion(+), 109 deletions(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 36b64756da34e..f46188a041aa0 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -946,7 +946,7 @@ where // array length computation, `typeck` may not have yet been run and errored out. In fact // most likey we *are* running `typeck` right now. Investigate whether we can bail out // on `typeck_tables().has_errors` at all const eval entry points. - error!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); throw_unsup!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); } // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr index 29aeb42898739..74de5dc9aaf82 100644 --- a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -1,111 +1,3 @@ -[ERROR rustc_mir::interpret::place] Size mismatch when transmuting! - src: OpTy { - op: Immediate( - Scalar( - 0x0000000000000001, - ), - ), - layout: TyLayout { - ty: usize, - details: LayoutDetails { - variants: Single { - index: 0, - }, - fields: Union( - 0, - ), - abi: Scalar( - Scalar { - value: Int( - I64, - false, - ), - valid_range: 0..=18446744073709551615, - }, - ), - largest_niche: None, - align: AbiAndPrefAlign { - abi: Align { - pow2: 3, - }, - pref: Align { - pow2: 3, - }, - }, - size: Size { - raw: 8, - }, - }, - }, - } - dest: PlaceTy { - place: Ptr( - MemPlace { - ptr: AllocId(0).0x0, - align: Align { - pow2: 3, - }, - meta: None, - }, - ), - layout: TyLayout { - ty: &[u8], - details: LayoutDetails { - variants: Single { - index: 0, - }, - fields: Arbitrary { - offsets: [ - Size { - raw: 0, - }, - Size { - raw: 8, - }, - ], - memory_index: [ - 0, - 1, - ], - }, - abi: ScalarPair( - Scalar { - value: Pointer, - valid_range: 1..=18446744073709551615, - }, - Scalar { - value: Int( - I64, - false, - ), - valid_range: 0..=18446744073709551615, - }, - ), - largest_niche: Some( - Niche { - offset: Size { - raw: 0, - }, - scalar: Scalar { - value: Pointer, - valid_range: 1..=18446744073709551615, - }, - }, - ), - align: AbiAndPrefAlign { - abi: Align { - pow2: 3, - }, - pref: Align { - pow2: 3, - }, - }, - size: Size { - raw: 16, - }, - }, - }, - } error: any use of this value will cause an error --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29 | From eabe066b96ea5855dac0e8ad837821a40e739fb4 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 13:13:08 +0100 Subject: [PATCH 26/35] Typo --- src/librustc_mir/interpret/intern.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 7463aaf509860..9dbe685813ef2 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -195,7 +195,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx // Validation has already errored on an invalid vtable pointer so we can safely not // do anything if this is not a real pointer. if let Scalar::Ptr(vtable) = mplace.meta.unwrap() { - // Explitly choose `Immutable` here, since vtables are immutable, even + // Explicitly choose `Immutable` here, since vtables are immutable, even // if the reference of the fat pointer is mutable. self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; } else { From af8ca7ad52892521d83813527c38beaae7ffcf60 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 13:30:47 +0100 Subject: [PATCH 27/35] Explain why `const_eval` is ok here --- src/librustc_mir/interpret/operand.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 78638a399482b..694ffaa83e40b 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -588,6 +588,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; + // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. + // The reason we use `const_eval_raw` everywhere else is to prevent cycles during + // validation, because validation automatically reads through any references, thus + // potentially requiring the current static to be evaluated again. This is not a + // problem here, because we need an operand and operands are always reads. + // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of + // `StaticKind` once and for all. let val = self.tcx.const_eval(param_env.and(GlobalId { instance, promoted: None }))?; // "recurse". This is only ever going into a recusion depth of 1, because after From 4c40bb7af6ba549f9276a69c257cd7fb0df17a5c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 20:39:35 +0100 Subject: [PATCH 28/35] Early abort instead of building up zero sized values --- src/librustc/mir/interpret/allocation.rs | 4 ---- src/librustc_mir/hair/pattern/_match.rs | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 957a028a59ebb..67f1c8072d680 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -127,10 +127,6 @@ impl Allocation { extra: (), } } - - pub fn zst(align: Align) -> Self { - Self::undef(Size::ZERO, align) - } } impl Allocation<(), ()> { diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 9851f24689744..c6efbe8833279 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -237,11 +237,11 @@ use super::{FieldPat, Pat, PatKind, PatRange}; use rustc::hir::def_id::DefId; use rustc::hir::{HirId, RangeEnd}; -use rustc::ty::layout::{Align, Integer, IntegerExt, Size, VariantIdx}; +use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx}; use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef}; use rustc::lint; -use rustc::mir::interpret::{truncate, AllocId, Allocation, ConstValue, Pointer, Scalar}; +use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc::mir::Field; use rustc::util::captures::Captures; use rustc::util::common::ErrorReported; @@ -2366,17 +2366,19 @@ fn specialize_one_pattern<'p, 'tcx>( let (alloc, offset, n, ty) = match value.ty.kind { ty::Array(t, n) => { let n = n.eval_usize(cx.tcx, cx.param_env); + // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce, + // the result would be exactly what we early return here. + if n == 0 { + if ctor_wild_subpatterns.len() as u64 == 0 { + return Some(PatStack::from_slice(&[])); + } else { + return None; + } + } match value.val { ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => { (Cow::Borrowed(alloc), offset, n, t) } - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })) - if n == 0 => - { - let align = Align::from_bytes(data as u64).unwrap(); - // empty array - (Cow::Owned(Allocation::zst(align)), Size::ZERO, 0, t) - } _ => span_bug!(pat.span, "array pattern is {:?}", value,), } } From 09dd13c7f781a0ae18c3a2e94ae20b284a90cf3a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 20:56:01 +0100 Subject: [PATCH 29/35] Add a `const_eval` helper to `InterpCx` --- src/librustc_mir/interpret/eval_context.rs | 22 ++++++++++++++++++++-- src/librustc_mir/interpret/intrinsics.rs | 5 ++--- src/librustc_mir/interpret/operand.rs | 16 +--------------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 76f74a3ecaa69..da4156c2719fd 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -20,8 +20,8 @@ use rustc_macros::HashStable; use syntax::source_map::{self, Span, DUMMY_SP}; use super::{ - Immediate, MPlaceTy, Machine, MemPlace, Memory, Operand, Place, PlaceTy, ScalarMaybeUndef, - StackPopInfo, + Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy, + ScalarMaybeUndef, StackPopInfo, }; pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { @@ -754,6 +754,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } + pub(super) fn const_eval( + &self, + gid: GlobalId<'tcx>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics + // and thus don't care about the parameter environment. While we could just use + // `self.param_env`, that would mean we invoke the query to evaluate the static + // with different parameter environments, thus causing the static to be evaluated + // multiple times. + let param_env = if self.tcx.is_static(gid.instance.def_id()) { + ty::ParamEnv::reveal_all() + } else { + self.param_env + }; + let val = self.tcx.const_eval(param_env.and(gid))?; + self.eval_const_to_op(val, None) + } + pub fn const_eval_raw( &self, gid: GlobalId<'tcx>, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 8e4dc87451c32..eb7657f780c56 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -118,9 +118,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::size_of | sym::type_id | sym::type_name => { - let val = - self.tcx.const_eval_instance(self.param_env, instance, Some(self.tcx.span))?; - let val = self.eval_const_to_op(val, None)?; + let gid = GlobalId { instance, promoted: None }; + let val = self.const_eval(gid)?; self.copy_op(val, dest)?; } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 694ffaa83e40b..fc63847433b5c 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -578,16 +578,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), ty::ConstKind::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; - // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics - // and thus don't care about the parameter environment. While we could just use - // `self.param_env`, that would mean we invoke the query to evaluate the static - // with different parameter environments, thus causing the static to be evaluated - // multiple times. - let param_env = if self.tcx.is_static(def_id) { - ty::ParamEnv::reveal_all() - } else { - self.param_env - }; // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. // The reason we use `const_eval_raw` everywhere else is to prevent cycles during // validation, because validation automatically reads through any references, thus @@ -595,11 +585,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // problem here, because we need an operand and operands are always reads. // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of // `StaticKind` once and for all. - let val = - self.tcx.const_eval(param_env.and(GlobalId { instance, promoted: None }))?; - // "recurse". This is only ever going into a recusion depth of 1, because after - // `const_eval` we don't have `Unevaluated` anymore. - return self.eval_const_to_op(val, layout); + return self.const_eval(GlobalId { instance, promoted: None }); } ty::ConstKind::Value(val_val) => val_val, }; From 79960b48366c5ea58506be054263d36c76bc85d4 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 21:28:25 +0100 Subject: [PATCH 30/35] Documentation nit --- src/librustc_mir/interpret/operand.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index fc63847433b5c..e37aa69dfde83 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -582,7 +582,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The reason we use `const_eval_raw` everywhere else is to prevent cycles during // validation, because validation automatically reads through any references, thus // potentially requiring the current static to be evaluated again. This is not a - // problem here, because we need an operand and operands are always reads. + // problem here, because we are building an operand which means an actual read is + // happening. // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of // `StaticKind` once and for all. return self.const_eval(GlobalId { instance, promoted: None }); From e9dc8601ec2afbec6a9bd44a85fe29d1edba4884 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 21:31:24 +0100 Subject: [PATCH 31/35] Reintroduce the recursion comment --- src/librustc_mir/interpret/eval_context.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index da4156c2719fd..bc158a767cef5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -769,6 +769,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env }; let val = self.tcx.const_eval(param_env.and(gid))?; + // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a + // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not + // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call + // `ecx.const_eval`. self.eval_const_to_op(val, None) } From aaf70150044191d1cc7362a49a72d4d8cc515a92 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Dec 2019 17:13:25 +0100 Subject: [PATCH 32/35] Use the targetted const eval functions --- src/librustc_mir/interpret/eval_context.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index bc158a767cef5..766ef6ab6feac 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -758,17 +758,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics - // and thus don't care about the parameter environment. While we could just use - // `self.param_env`, that would mean we invoke the query to evaluate the static - // with different parameter environments, thus causing the static to be evaluated - // multiple times. - let param_env = if self.tcx.is_static(gid.instance.def_id()) { - ty::ParamEnv::reveal_all() + let val = if self.tcx.is_static(gid.instance.def_id()) { + self.tcx.const_eval_poly(gid.instance.def_id())? + } else if let Some(promoted) = gid.promoted { + self.tcx.const_eval_promoted(gid.instance, promoted)? } else { - self.param_env + self.tcx.const_eval_instance(self.param_env, gid.instance, Some(self.tcx.span))? }; - let val = self.tcx.const_eval(param_env.and(gid))?; // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call From 65bb8055c079a9034bd08d6ba198975608eafbd9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Dec 2019 17:13:50 +0100 Subject: [PATCH 33/35] Fix rebase fallout --- src/librustc_mir/interpret/intrinsics.rs | 2 +- src/librustc_mir/interpret/operand.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index eb7657f780c56..da7cff97ee2c2 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::{ self, - interpret::{ConstValue, InterpResult, Scalar}, + interpret::{ConstValue, GlobalId, InterpResult, Scalar}, BinOp, }; use rustc::ty; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index e37aa69dfde83..def979b63b52a 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -588,6 +588,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `StaticKind` once and for all. return self.const_eval(GlobalId { instance, promoted: None }); } + ty::ConstKind::Infer(..) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Placeholder(..) => { + bug!("eval_const_to_op: Unexpected ConstKind {:?}", val) + } ty::ConstKind::Value(val_val) => val_val, }; // Other cases need layout. From cefeb663666de29b42a4c233bee14793712613ae Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Mon, 23 Dec 2019 23:31:39 +0000 Subject: [PATCH 34/35] Use the chocolatey CDN directly to avoid the flaky API --- src/ci/scripts/install-msys2.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh index 3a78ef209e4e5..9e899ba9d8947 100755 --- a/src/ci/scripts/install-msys2.sh +++ b/src/ci/scripts/install-msys2.sh @@ -12,10 +12,14 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows; then - for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10; do - choco install msys2 \ - --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress \ - && mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}" \ - && ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin" && break - done + # Pre-followed the api/v2 URL to the CDN since the API can be a bit flakey + curl -sSL https://packages.chocolatey.org/msys2.20190524.0.0.20191030.nupkg > \ + msys2.nupkg + curl -sSL https://packages.chocolatey.org/chocolatey-core.extension.1.3.5.1.nupkg > \ + chocolatey-core.extension.nupkg + choco install -s . msys2 \ + --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress + rm msys2.nupkg chocolatey-core.extension.nupkg + mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}" + ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin" fi From df4d490038c37e441065890fa27ed2ce0bdf83e6 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 23 Dec 2019 15:40:20 -0500 Subject: [PATCH 35/35] Minimize unsafety in encode_utf8 Use slice patterns to avoid having to skip bounds checking --- src/libcore/char/methods.rs | 59 ++++++++++++++++++------------------- src/libcore/lib.rs | 1 + 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index bb6d6db57d214..fe5d16862a6a6 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -434,36 +434,35 @@ impl char { #[inline] pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { let code = self as u32; - // SAFETY: each arm checks the size of the slice and only uses `get_unchecked` unsafe ops - unsafe { - let len = if code < MAX_ONE_B && !dst.is_empty() { - *dst.get_unchecked_mut(0) = code as u8; - 1 - } else if code < MAX_TWO_B && dst.len() >= 2 { - *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B && dst.len() >= 3 { - *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; - 3 - } else if dst.len() >= 4 { - *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; - 4 - } else { - panic!( - "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf8(), - code, - dst.len(), - ) - }; - from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) - } + let len = self.len_utf8(); + match (len, &mut dst[..]) { + (1, [a, ..]) => { + *a = code as u8; + } + (2, [a, b, ..]) => { + *a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *b = (code & 0x3F) as u8 | TAG_CONT; + } + (3, [a, b, c, ..]) => { + *a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *b = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *c = (code & 0x3F) as u8 | TAG_CONT; + } + (4, [a, b, c, d, ..]) => { + *a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *b = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *d = (code & 0x3F) as u8 | TAG_CONT; + } + _ => panic!( + "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + len, + code, + dst.len(), + ), + }; + // SAFETY: We just wrote UTF-8 content in, so converting to str is fine. + unsafe { from_utf8_unchecked_mut(&mut dst[..len]) } } /// Encodes this character as UTF-16 into the provided `u16` buffer, diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d12aebb87b975..7d11dd2800fd4 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -129,6 +129,7 @@ #![feature(associated_type_bounds)] #![feature(const_type_id)] #![feature(const_caller_location)] +#![feature(slice_patterns)] #[prelude_import] #[allow(unused)]