Change:
The original problem got fixed by avoiding the broken code paths; this issue now tracks . In we have a  trait which gives you a generic way to do null pointer checks. A user recently reported that the crate no longer compiles on () because type validation detects that and create uninitialized raw pointers. I can reproduce this with the latest nightly, . Is the use shown in that playground example ( on a ) actually UB? Also, I noticed that calling the method defined on a raw pointer with doesn't trigger this error, implying that the problem isn't with declaring a constant that contains a null pointer (), but the fact that we're using it for a comparison. Was this intended, or is it just an oversight in the error detection code? <details<summaryFull example with output</summary</detailsCC: because it looks like they were the last person to touch that error message (). <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --This issue has been assigned to via . <!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
Cc This is definitely not intended, that example you gave is entirely safe code and should compile just fine. The odd thing is, I am indeed responsible for the error but that was back in which has long arrived on stable -- so the error itself cannot be the source of the regression. Would be good to get the regression narrowed down a bit more. I also don't understand why seems to be needed to trigger this. Might be some interaction with promotion? The error message is probably (hopefully!) just wrong, I doubt the pointer is actually uninitialized. We just show that error when anything goes wrong in this line: Likely really doesn't like that the pointer is NULL. The thing is, this code works fine, and that just makes no sense:
ping bisect
Hey Cleanup Crew ICE-breakers! This bug has been identified as a good "Cleanup ICE-breaking candidate". In case it's useful, here are some [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 [instructions]: https://rustc-dev- cc
It's not an ICE, but if ICE-breakers also help with other bisects then yes this would be awesome. :)
If it helps pinpoint when the error was introduced, my is usually within a couple days of the latest and I made a release of that crate on 2020-04-07 without hitting any compilation errors.
Regression in nightly-2020-04-17. Looking currently for regression commit between 2020-04-17 and 2020-04-16. searched nightlies: from nightly-2020-04-07 to nightly-2020-04-19 regressed nightly: nightly-2020-04-17 searched commits: from to regressed commit: Full Log: <details</details
If it regressed in , I guess the only PR that could have caused this is ? It might explain why is needed to trigger the error. Otherwise the culprit might be ?
My guess would've been
awesome, thanks a lot. I am very sure it's not , that would ICE complaining about bad types in a function call. I doubt it's , that doesn't sound likely to me. My guess is that it's (Cc which affects const-prop and what code const-eval gets run on. But still that doesn't explain why it would suddenly stop liking NULL pointers. In fact it's not just NULL, this also fails: Hm... actually... that const-prop change will mean we run const-prop on some generic code. Maybe it tries to evaluate that test up there, but because the code is generic cannot actually evaluate enough operands and then some stuff is still uninitialized.
Bingo, the also points at const-prop: <details<summarybacktrace where errors is created</summary</details
So it is probably this call that is failing:
Oops, I meant . I can't even copy-paste correcly
But then it gets weird. We end up here: and then here And then somehow we end up evaluating a const (?!?) even though we just wanted to subst on a (not eval, that would be the next thing does). And that evaluation goes very wrong as the const is somehow not initialized.
I can see it evaluating . That is quite strange because we don't actually know , so this really cannot be evaluated... but somehow we do not have sanity checks that catch this?
We already have a very similar test for Nullable. It's curious that it didn't catch this. Ah, changing the test case to and adding reproduces the error.
Ah, good catch! Probably it was a mistake to not add there in the first place, because built as a binary these are just dead code. The test was in
claim
Independent of what we do on master, I propose that to fix the regression on beta (which just recently branched, with this bug) we revert in that branch. The change is diagnostics-only, it's a tiny patch, I think the risk is very low. Is it okay to make that a beta-only PR?
Maybe ask
Yeah, anything that just needs a fix on beta (and we want an entirely different fix on master) can be a beta-only PR, though likely I should not the reviewer for it.
See for some more analysis and a proposed solution.
Namely, the proposed solution is to: Equip with a pattern of errors to catch, the rest is forwarded. (Figuring out all the right patterns will take a few runs of the test suite here.) Forward errors out of validation instead of ICEing.
The beta PR landed, master PR by is on the way.
This bug is now fixed, so I will remove all the critical label. But let's keep this open to track the issue of validation swallowing errors.
The reversion on master landed on PR . Still need to assign a priority to the remaining issue of validation swallowing errors, so ... prioritize
Assigning as and removing .
As this problem raised in the Crater run, should be nominated to be backported to beta?
My understanding is that was the intended fix for beta and we expect to go with the trains, i.e. there is no need for a backport. But if I'm wrong, we should indeed nominate it.
Oh right, I re-read
Indeed, the beta fix was to revert the original incorrect PR. This PR that just landed now just fixed , which doesn't need backporting. However, I am going to re-open this issue because validation still swallows layout errors in many cases -- just this one particular case got fixed.

Discussion:
use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; <ins> use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo}; </ins> use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::symbol::{sym, Symbol};

}; macro_rules! throw_validation_failure { <del> ($what:expr, $where:expr, $details:expr) => {{ let mut msg = format!("encountered {}", $what); let where_ = &$where; if !where_.is_empty() { msg.push_str(" at "); write_path(&mut msg, where_); } write!(&mut msg, ", but expected {}", $details).unwrap(); throw_ub!(ValidationFailure(msg)) }}; ($what:expr, $where:expr) => {{ </del> <ins> ($what:expr, $where:expr $(, $details:expr )?) => {{ </ins> let mut msg = format!("encountered {}", $what); let where_ = &$where; if !where_.is_empty() { msg.push_str(" at "); write_path(&mut msg, where_); } <ins> $( write!(&mut msg, ", but expected {}", $details).unwrap(); )? </ins> throw_ub!(ValidationFailure(msg)) }}; } <ins> /// Returns a validation failure for any Err value of $e. // FIXME: Replace all usages of try_validation! with try_validation_pat!. </ins> macro_rules! try_validation { <del> ($e:expr, $what:expr, $where:expr, $details:expr) => {{ match $e { Ok(x) => x, // We re-throw the error, so we are okay with allocation: // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where, $details), } </del> <ins> ($e:expr, $what:expr, $where:expr $(, $details:expr )?) => {{ try_validation_pat!($e, _, $what, $where $(, $details )?) </ins> }}; <del> ($e:expr, $what:expr, $where:expr) => {{ </del> <ins> } /// Like try_validation, but will throw a validation error if any of the patterns in $p are /// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns /// as a kind of validation blacklist: /// /// ```rust /// let v = try_validation_pat!(some_fn(), Foo | Bar | Baz, "some failure", path); /// // Failures that match $p are thrown up as validation errors, but other errors are passed back /// // unchanged. /// ``` macro_rules! try_validation_pat { ($e:expr, $( $p:pat )|*, $what:expr, $where:expr $(, $details:expr )?) => {{ </ins> match $e { Ok(x) => x, <del> // We re-throw the error, so we are okay with allocation: // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where), </del> <ins> // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. $( Err(InterpErrorInfo { kind: $p, .. }) )|* if true => throw_validation_failure!($what, $where $(, $details)?), Err(e) => Err::<!, _>(e)?, </ins> } }}; }

// We are conservative with undef for integers, but try to // actually enforce the strict rules for raw pointers (mostly because // that lets us re-use `ref_to_mplace`). <del> let place = try_validation!( </del> <ins> let place = try_validation_pat!( </ins> self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), <ins> err_ub!(InvalidUndefBytes(..)), </ins> "uninitialized raw pointer", self.path );

// Run it. match visitor.visit_value(op) { Ok(()) => Ok(()), <del> // We should only get validation errors here. Avoid other errors as // those do not show *where* in the value the issue lies. </del> <ins> // Pass through validation failures. </ins> Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err), <ins> // Also pass through InvalidProgram, those just indicate that we could not // validate and each caller will know best what to do with them. Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err), // Avoid other errors as those do not show *where* in the value the issue lies. </ins> Err(err) => bug!("Unexpected error during validation: {}", err), } }

return None; } <del> // FIXME we need to revisit this for #67176 if rvalue.needs_subst() { return None; } </del> // Perform any special handling for specific Rvalue types. // Generally, checks here fall into one of two categories: //   1. Additional checking to provide useful lints to the user

_ => {} } <ins> // FIXME we need to revisit this for #67176 if rvalue.needs_subst() { return None; } </ins> self.use_ecx(|this| { trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); this.ecx.eval_rvalue_into_place(rvalue, place)?;

<del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:22:13 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:17:20 </ins> | <del> LL |     let _ = x << 42; |             ^^^^^^^ attempt to shift left with overflow </del> <ins> LL |     const N: i32 = T::N << 42; |                    ^^^^^^^^^^ attempt to shift left with overflow </ins> | note: the lint level is defined here <del> --> $DIR/lint-exceeding-bitshifts.rs:9:9 </del> <ins> --> $DIR/lint-exceeding-bitshifts.rs:8:9 </ins> | <del> LL | #![deny(arithmetic_overflow, const_err)] </del> <ins> LL | #![warn(arithmetic_overflow, const_err)] </ins> |         ^^^^^^^^^^^^^^^^^^^ <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:27:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:21:13 | LL |     let _ = x << 42; |             ^^^^^^^ attempt to shift left with overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:26:15 </ins> | LL |       let n = 1u8 << 8; |               ^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:29:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:28:15 </ins> | LL |       let n = 1u16 << 16; |               ^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:31:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:30:15 </ins> | LL |       let n = 1u32 << 32; |               ^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:33:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:32:15 </ins> | LL |       let n = 1u64 << 64; |               ^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:35:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:34:15 </ins> | LL |       let n = 1i8 << 8; |               ^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:37:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:36:15 </ins> | LL |       let n = 1i16 << 16; |               ^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:39:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:38:15 </ins> | LL |       let n = 1i32 << 32; |               ^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:41:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:40:15 </ins> | LL |       let n = 1i64 << 64; |               ^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:43:15 </ins> | LL |       let n = 1u8 >> 8; |               ^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:46:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:45:15 </ins> | LL |       let n = 1u16 >> 16; |               ^^^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:48:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:47:15 </ins> | LL |       let n = 1u32 >> 32; |               ^^^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:50:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:49:15 </ins> | LL |       let n = 1u64 >> 64; |               ^^^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:52:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:51:15 </ins> | LL |       let n = 1i8 >> 8; |               ^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:54:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:53:15 </ins> | LL |       let n = 1i16 >> 16; |               ^^^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:56:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:55:15 </ins> | LL |       let n = 1i32 >> 32; |               ^^^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:58:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:57:15 </ins> | LL |       let n = 1i64 >> 64; |               ^^^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:62:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:61:15 </ins> | LL |       let n = n << 8; |               ^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:64:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:63:15 </ins> | LL |       let n = 1u8 << -8; |               ^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:69:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:68:15 </ins> | LL |       let n = 1u8 << (4+4); |               ^^^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:71:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:70:15 </ins> | LL |       let n = 1i64 >> [64][0]; |               ^^^^^^^^^^^^^^^ attempt to shift right with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:76:15 </ins> | LL |       let n = 1_isize << BITS; |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow <del> error: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:78:15 </del> <ins> warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 </ins> | LL |       let n = 1_usize << BITS; |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow <del> error: aborting due to 23 previous errors </del> <ins> warning: 24 warnings emitted </ins>

//[noopt]compile-flags: -C opt-level=0 //[opt]compile-flags: -O //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O <del> // build-fail </del> <ins> // build-pass </ins> #![crate_type="lib"] <del> #![deny(arithmetic_overflow, const_err)] </del> <ins> #![warn(arithmetic_overflow, const_err)] </ins> #![allow(unused_variables)] #![allow(dead_code)]

} impl<T: Foo> Foo for Vec<T> { <del> const N: i32 = T::N << 42; // FIXME this should warn </del> <ins> const N: i32 = T::N << 42; //~ WARN: arithmetic operation will overflow </ins> } pub fn foo(x: i32) { <del> let _ = x << 42; //~ ERROR: arithmetic operation will overflow </del> <ins> let _ = x << 42; //~ WARN: arithmetic operation will overflow </ins> } pub fn main() { let n = 1u8 << 7; <del> let n = 1u8 << 8;   //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u8 << 8;   //~ WARN: arithmetic operation will overflow </ins> let n = 1u16 << 15; <del> let n = 1u16 << 16; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u16 << 16; //~ WARN: arithmetic operation will overflow </ins> let n = 1u32 << 31; <del> let n = 1u32 << 32; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u32 << 32; //~ WARN: arithmetic operation will overflow </ins> let n = 1u64 << 63; <del> let n = 1u64 << 64; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u64 << 64; //~ WARN: arithmetic operation will overflow </ins> let n = 1i8 << 7; <del> let n = 1i8 << 8;   //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i8 << 8;   //~ WARN: arithmetic operation will overflow </ins> let n = 1i16 << 15; <del> let n = 1i16 << 16; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i16 << 16; //~ WARN: arithmetic operation will overflow </ins> let n = 1i32 << 31; <del> let n = 1i32 << 32; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i32 << 32; //~ WARN: arithmetic operation will overflow </ins> let n = 1i64 << 63; <del> let n = 1i64 << 64; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i64 << 64; //~ WARN: arithmetic operation will overflow </ins> let n = 1u8 >> 7; <del> let n = 1u8 >> 8;   //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u8 >> 8;   //~ WARN: arithmetic operation will overflow </ins> let n = 1u16 >> 15; <del> let n = 1u16 >> 16; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u16 >> 16; //~ WARN: arithmetic operation will overflow </ins> let n = 1u32 >> 31; <del> let n = 1u32 >> 32; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u32 >> 32; //~ WARN: arithmetic operation will overflow </ins> let n = 1u64 >> 63; <del> let n = 1u64 >> 64; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u64 >> 64; //~ WARN: arithmetic operation will overflow </ins> let n = 1i8 >> 7; <del> let n = 1i8 >> 8;   //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i8 >> 8;   //~ WARN: arithmetic operation will overflow </ins> let n = 1i16 >> 15; <del> let n = 1i16 >> 16; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i16 >> 16; //~ WARN: arithmetic operation will overflow </ins> let n = 1i32 >> 31; <del> let n = 1i32 >> 32; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i32 >> 32; //~ WARN: arithmetic operation will overflow </ins> let n = 1i64 >> 63; <del> let n = 1i64 >> 64; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i64 >> 64; //~ WARN: arithmetic operation will overflow </ins> let n = 1u8; let n = n << 7; <del> let n = n << 8; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = n << 8; //~ WARN: arithmetic operation will overflow </ins> <del> let n = 1u8 << -8; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u8 << -8; //~ WARN: arithmetic operation will overflow </ins> let n = 1i8<<(1isize+-1); let n = 1u8 << (4+3); <del> let n = 1u8 << (4+4); //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1u8 << (4+4); //~ WARN: arithmetic operation will overflow </ins> let n = 1i64 >> [63][0]; <del> let n = 1i64 >> [64][0]; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1i64 >> [64][0]; //~ WARN: arithmetic operation will overflow </ins> #[cfg(target_pointer_width = "32")] const BITS: usize = 32; #[cfg(target_pointer_width = "64")] const BITS: usize = 64; <del> let n = 1_isize << BITS; //~ ERROR: arithmetic operation will overflow let n = 1_usize << BITS; //~ ERROR: arithmetic operation will overflow </del> <ins> let n = 1_isize << BITS; //~ WARN: arithmetic operation will overflow let n = 1_usize << BITS; //~ WARN: arithmetic operation will overflow </ins> }