Skip to content

Commit 5b17290

Browse files
authored
Rollup merge of #71663 - jumbatm:caller-handles-validation-error, r=RalfJung
Fix exceeding bitshifts not emitting for assoc. consts (properly this time, I swear!) Fixes #69021 and fixes #71353. As described in #71353 (comment), this PR: - adds a variant of `try_validation!` called `try_validation_pat!` that allows specific failures to be turned into validation failures (but returns the rest, unchanged), and - allows `InvalidProgram` to be returned out of validation r? @RalfJung
2 parents 6f5de87 + bd18ad4 commit 5b17290

6 files changed

+263
-216
lines changed

src/librustc_mir/interpret/validity.rs

+61-31
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::ops::RangeInclusive;
1111

1212
use rustc_data_structures::fx::FxHashSet;
1313
use rustc_hir as hir;
14+
use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
1415
use rustc_middle::ty;
1516
use rustc_middle::ty::layout::TyAndLayout;
1617
use rustc_span::symbol::{sym, Symbol};
@@ -24,43 +25,71 @@ use super::{
2425
};
2526

2627
macro_rules! throw_validation_failure {
27-
($what:expr, $where:expr, $details:expr) => {{
28-
let mut msg = format!("encountered {}", $what);
29-
let where_ = &$where;
30-
if !where_.is_empty() {
31-
msg.push_str(" at ");
32-
write_path(&mut msg, where_);
33-
}
34-
write!(&mut msg, ", but expected {}", $details).unwrap();
35-
throw_ub!(ValidationFailure(msg))
36-
}};
37-
($what:expr, $where:expr) => {{
28+
($what:expr, $where:expr $(, $expected:expr )?) => {{
3829
let mut msg = format!("encountered {}", $what);
3930
let where_ = &$where;
4031
if !where_.is_empty() {
4132
msg.push_str(" at ");
4233
write_path(&mut msg, where_);
4334
}
35+
$( write!(&mut msg, ", but expected {}", $expected).unwrap(); )?
4436
throw_ub!(ValidationFailure(msg))
4537
}};
4638
}
4739

40+
/// Returns a validation failure for any Err value of $e.
41+
// FIXME: Replace all usages of try_validation! with try_validation_pat!.
4842
macro_rules! try_validation {
49-
($e:expr, $what:expr, $where:expr, $details:expr) => {{
50-
match $e {
51-
Ok(x) => x,
52-
// We re-throw the error, so we are okay with allocation:
53-
// this can only slow down builds that fail anyway.
54-
Err(_) => throw_validation_failure!($what, $where, $details),
55-
}
43+
($e:expr, $what:expr, $where:expr $(, $expected:expr )?) => {{
44+
try_validation_pat!($e, $where, {
45+
_ => { "{}", $what } $( expected { "{}", $expected } )?,
46+
})
5647
}};
57-
58-
($e:expr, $what:expr, $where:expr) => {{
48+
}
49+
/// Like try_validation, but will throw a validation error if any of the patterns in $p are
50+
/// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns
51+
/// as a kind of validation blacklist:
52+
///
53+
/// ```
54+
/// let v = try_validation_pat!(some_fn(), some_path, {
55+
/// Foo | Bar | Baz => { "some failure" },
56+
/// });
57+
/// // Failures that match $p are thrown up as validation errors, but other errors are passed back
58+
/// // unchanged.
59+
/// ```
60+
///
61+
/// An additional expected parameter can also be added to the failure message:
62+
///
63+
/// ```
64+
/// let v = try_validation_pat!(some_fn(), some_path, {
65+
/// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" },
66+
/// });
67+
/// ```
68+
///
69+
/// An additional nicety is that both parameters actually take format args, so you can just write
70+
/// the format string in directly:
71+
///
72+
/// ```
73+
/// let v = try_validation_pat!(some_fn(), some_path, {
74+
/// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value },
75+
/// });
76+
/// ```
77+
///
78+
macro_rules! try_validation_pat {
79+
($e:expr, $where:expr, { $( $p:pat )|+ =>
80+
{ $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? $( , )?}) => {{
5981
match $e {
6082
Ok(x) => x,
61-
// We re-throw the error, so we are okay with allocation:
62-
// this can only slow down builds that fail anyway.
63-
Err(_) => throw_validation_failure!($what, $where),
83+
// We catch the error and turn it into a validation failure. We are okay with
84+
// allocation here as this can only slow down builds that fail anyway.
85+
$( Err(InterpErrorInfo { kind: $p, .. }) )|+ =>
86+
throw_validation_failure!(
87+
format_args!($( $what_fmt ),+),
88+
$where
89+
$(, format_args!($( $expected_fmt ),+))?
90+
),
91+
#[allow(unreachable_patterns)]
92+
Err(e) => Err::<!, _>(e)?,
6493
}
6594
}};
6695
}
@@ -492,11 +521,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
492521
// We are conservative with undef for integers, but try to
493522
// actually enforce the strict rules for raw pointers (mostly because
494523
// that lets us re-use `ref_to_mplace`).
495-
let place = try_validation!(
496-
self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
497-
"uninitialized raw pointer",
498-
self.path
499-
);
524+
let place = try_validation_pat!(self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), self.path, {
525+
err_ub!(InvalidUndefBytes(..)) => { "uninitialized raw pointer" },
526+
});
500527
if place.layout.is_unsized() {
501528
self.check_wide_ptr_meta(place.meta, place.layout)?;
502529
}
@@ -800,7 +827,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
800827

801828
throw_validation_failure!("uninitialized bytes", self.path)
802829
}
803-
// Other errors shouldn't be possible
830+
// Propagate upwards (that will also check for unexpected errors).
804831
_ => return Err(err),
805832
}
806833
}
@@ -843,9 +870,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
843870
// Run it.
844871
match visitor.visit_value(op) {
845872
Ok(()) => Ok(()),
846-
// We should only get validation errors here. Avoid other errors as
847-
// those do not show *where* in the value the issue lies.
873+
// Pass through validation failures.
848874
Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err),
875+
// Also pass through InvalidProgram, those just indicate that we could not
876+
// validate and each caller will know best what to do with them.
877+
Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err),
878+
// Avoid other errors as those do not show *where* in the value the issue lies.
849879
Err(err) => bug!("Unexpected error during validation: {}", err),
850880
}
851881
}

src/librustc_mir/transform/const_prop.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -549,11 +549,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
549549
return None;
550550
}
551551

552-
// FIXME we need to revisit this for #67176
553-
if rvalue.needs_subst() {
554-
return None;
555-
}
556-
557552
// Perform any special handling for specific Rvalue types.
558553
// Generally, checks here fall into one of two categories:
559554
// 1. Additional checking to provide useful lints to the user
@@ -594,6 +589,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
594589
_ => {}
595590
}
596591

592+
// FIXME we need to revisit this for #67176
593+
if rvalue.needs_subst() {
594+
return None;
595+
}
596+
597597
self.use_ecx(|this| {
598598
trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
599599
this.ecx.eval_rvalue_into_place(rvalue, place)?;
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,152 @@
1-
error: this arithmetic operation will overflow
2-
--> $DIR/lint-exceeding-bitshifts.rs:22:13
1+
warning: this arithmetic operation will overflow
2+
--> $DIR/lint-exceeding-bitshifts.rs:17:20
33
|
4-
LL | let _ = x << 42;
5-
| ^^^^^^^ attempt to shift left with overflow
4+
LL | const N: i32 = T::N << 42;
5+
| ^^^^^^^^^^ attempt to shift left with overflow
66
|
77
note: the lint level is defined here
8-
--> $DIR/lint-exceeding-bitshifts.rs:9:9
8+
--> $DIR/lint-exceeding-bitshifts.rs:8:9
99
|
10-
LL | #![deny(arithmetic_overflow, const_err)]
10+
LL | #![warn(arithmetic_overflow, const_err)]
1111
| ^^^^^^^^^^^^^^^^^^^
1212

13-
error: this arithmetic operation will overflow
14-
--> $DIR/lint-exceeding-bitshifts.rs:27:15
13+
warning: this arithmetic operation will overflow
14+
--> $DIR/lint-exceeding-bitshifts.rs:21:13
15+
|
16+
LL | let _ = x << 42;
17+
| ^^^^^^^ attempt to shift left with overflow
18+
19+
warning: this arithmetic operation will overflow
20+
--> $DIR/lint-exceeding-bitshifts.rs:26:15
1521
|
1622
LL | let n = 1u8 << 8;
1723
| ^^^^^^^^ attempt to shift left with overflow
1824

19-
error: this arithmetic operation will overflow
20-
--> $DIR/lint-exceeding-bitshifts.rs:29:15
25+
warning: this arithmetic operation will overflow
26+
--> $DIR/lint-exceeding-bitshifts.rs:28:15
2127
|
2228
LL | let n = 1u16 << 16;
2329
| ^^^^^^^^^^ attempt to shift left with overflow
2430

25-
error: this arithmetic operation will overflow
26-
--> $DIR/lint-exceeding-bitshifts.rs:31:15
31+
warning: this arithmetic operation will overflow
32+
--> $DIR/lint-exceeding-bitshifts.rs:30:15
2733
|
2834
LL | let n = 1u32 << 32;
2935
| ^^^^^^^^^^ attempt to shift left with overflow
3036

31-
error: this arithmetic operation will overflow
32-
--> $DIR/lint-exceeding-bitshifts.rs:33:15
37+
warning: this arithmetic operation will overflow
38+
--> $DIR/lint-exceeding-bitshifts.rs:32:15
3339
|
3440
LL | let n = 1u64 << 64;
3541
| ^^^^^^^^^^ attempt to shift left with overflow
3642

37-
error: this arithmetic operation will overflow
38-
--> $DIR/lint-exceeding-bitshifts.rs:35:15
43+
warning: this arithmetic operation will overflow
44+
--> $DIR/lint-exceeding-bitshifts.rs:34:15
3945
|
4046
LL | let n = 1i8 << 8;
4147
| ^^^^^^^^ attempt to shift left with overflow
4248

43-
error: this arithmetic operation will overflow
44-
--> $DIR/lint-exceeding-bitshifts.rs:37:15
49+
warning: this arithmetic operation will overflow
50+
--> $DIR/lint-exceeding-bitshifts.rs:36:15
4551
|
4652
LL | let n = 1i16 << 16;
4753
| ^^^^^^^^^^ attempt to shift left with overflow
4854

49-
error: this arithmetic operation will overflow
50-
--> $DIR/lint-exceeding-bitshifts.rs:39:15
55+
warning: this arithmetic operation will overflow
56+
--> $DIR/lint-exceeding-bitshifts.rs:38:15
5157
|
5258
LL | let n = 1i32 << 32;
5359
| ^^^^^^^^^^ attempt to shift left with overflow
5460

55-
error: this arithmetic operation will overflow
56-
--> $DIR/lint-exceeding-bitshifts.rs:41:15
61+
warning: this arithmetic operation will overflow
62+
--> $DIR/lint-exceeding-bitshifts.rs:40:15
5763
|
5864
LL | let n = 1i64 << 64;
5965
| ^^^^^^^^^^ attempt to shift left with overflow
6066

61-
error: this arithmetic operation will overflow
62-
--> $DIR/lint-exceeding-bitshifts.rs:44:15
67+
warning: this arithmetic operation will overflow
68+
--> $DIR/lint-exceeding-bitshifts.rs:43:15
6369
|
6470
LL | let n = 1u8 >> 8;
6571
| ^^^^^^^^ attempt to shift right with overflow
6672

67-
error: this arithmetic operation will overflow
68-
--> $DIR/lint-exceeding-bitshifts.rs:46:15
73+
warning: this arithmetic operation will overflow
74+
--> $DIR/lint-exceeding-bitshifts.rs:45:15
6975
|
7076
LL | let n = 1u16 >> 16;
7177
| ^^^^^^^^^^ attempt to shift right with overflow
7278

73-
error: this arithmetic operation will overflow
74-
--> $DIR/lint-exceeding-bitshifts.rs:48:15
79+
warning: this arithmetic operation will overflow
80+
--> $DIR/lint-exceeding-bitshifts.rs:47:15
7581
|
7682
LL | let n = 1u32 >> 32;
7783
| ^^^^^^^^^^ attempt to shift right with overflow
7884

79-
error: this arithmetic operation will overflow
80-
--> $DIR/lint-exceeding-bitshifts.rs:50:15
85+
warning: this arithmetic operation will overflow
86+
--> $DIR/lint-exceeding-bitshifts.rs:49:15
8187
|
8288
LL | let n = 1u64 >> 64;
8389
| ^^^^^^^^^^ attempt to shift right with overflow
8490

85-
error: this arithmetic operation will overflow
86-
--> $DIR/lint-exceeding-bitshifts.rs:52:15
91+
warning: this arithmetic operation will overflow
92+
--> $DIR/lint-exceeding-bitshifts.rs:51:15
8793
|
8894
LL | let n = 1i8 >> 8;
8995
| ^^^^^^^^ attempt to shift right with overflow
9096

91-
error: this arithmetic operation will overflow
92-
--> $DIR/lint-exceeding-bitshifts.rs:54:15
97+
warning: this arithmetic operation will overflow
98+
--> $DIR/lint-exceeding-bitshifts.rs:53:15
9399
|
94100
LL | let n = 1i16 >> 16;
95101
| ^^^^^^^^^^ attempt to shift right with overflow
96102

97-
error: this arithmetic operation will overflow
98-
--> $DIR/lint-exceeding-bitshifts.rs:56:15
103+
warning: this arithmetic operation will overflow
104+
--> $DIR/lint-exceeding-bitshifts.rs:55:15
99105
|
100106
LL | let n = 1i32 >> 32;
101107
| ^^^^^^^^^^ attempt to shift right with overflow
102108

103-
error: this arithmetic operation will overflow
104-
--> $DIR/lint-exceeding-bitshifts.rs:58:15
109+
warning: this arithmetic operation will overflow
110+
--> $DIR/lint-exceeding-bitshifts.rs:57:15
105111
|
106112
LL | let n = 1i64 >> 64;
107113
| ^^^^^^^^^^ attempt to shift right with overflow
108114

109-
error: this arithmetic operation will overflow
110-
--> $DIR/lint-exceeding-bitshifts.rs:62:15
115+
warning: this arithmetic operation will overflow
116+
--> $DIR/lint-exceeding-bitshifts.rs:61:15
111117
|
112118
LL | let n = n << 8;
113119
| ^^^^^^ attempt to shift left with overflow
114120

115-
error: this arithmetic operation will overflow
116-
--> $DIR/lint-exceeding-bitshifts.rs:64:15
121+
warning: this arithmetic operation will overflow
122+
--> $DIR/lint-exceeding-bitshifts.rs:63:15
117123
|
118124
LL | let n = 1u8 << -8;
119125
| ^^^^^^^^^ attempt to shift left with overflow
120126

121-
error: this arithmetic operation will overflow
122-
--> $DIR/lint-exceeding-bitshifts.rs:69:15
127+
warning: this arithmetic operation will overflow
128+
--> $DIR/lint-exceeding-bitshifts.rs:68:15
123129
|
124130
LL | let n = 1u8 << (4+4);
125131
| ^^^^^^^^^^^^ attempt to shift left with overflow
126132

127-
error: this arithmetic operation will overflow
128-
--> $DIR/lint-exceeding-bitshifts.rs:71:15
133+
warning: this arithmetic operation will overflow
134+
--> $DIR/lint-exceeding-bitshifts.rs:70:15
129135
|
130136
LL | let n = 1i64 >> [64][0];
131137
| ^^^^^^^^^^^^^^^ attempt to shift right with overflow
132138

133-
error: this arithmetic operation will overflow
134-
--> $DIR/lint-exceeding-bitshifts.rs:77:15
139+
warning: this arithmetic operation will overflow
140+
--> $DIR/lint-exceeding-bitshifts.rs:76:15
135141
|
136142
LL | let n = 1_isize << BITS;
137143
| ^^^^^^^^^^^^^^^ attempt to shift left with overflow
138144

139-
error: this arithmetic operation will overflow
140-
--> $DIR/lint-exceeding-bitshifts.rs:78:15
145+
warning: this arithmetic operation will overflow
146+
--> $DIR/lint-exceeding-bitshifts.rs:77:15
141147
|
142148
LL | let n = 1_usize << BITS;
143149
| ^^^^^^^^^^^^^^^ attempt to shift left with overflow
144150

145-
error: aborting due to 23 previous errors
151+
warning: 24 warnings emitted
146152

0 commit comments

Comments
 (0)