Skip to content

Commit 5e3a038

Browse files
Check for && and || in the HIR const-checker
1 parent 01c33e9 commit 5e3a038

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3851,6 +3851,7 @@ dependencies = [
38513851
"rustc_feature",
38523852
"rustc_hir",
38533853
"rustc_index",
3854+
"rustc_mir",
38543855
"rustc_session",
38553856
"rustc_span",
38563857
"rustc_target",

src/librustc_mir/transform/check_consts/validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
580580

581581
StatementKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
582582

583-
// Try to ensure that no `match` expressions have gotten throught the HIR const-checker.
583+
// Try to ensure that no `match` expressions have gotten through the HIR const-checker.
584584
StatementKind::FakeRead(FakeReadCause::ForMatchGuard, _)
585585
| StatementKind::FakeRead(FakeReadCause::ForGuardBinding, _)
586586
| StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {

src/librustc_passes/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
1616
rustc_errors = { path = "../librustc_errors" }
1717
rustc_feature = { path = "../librustc_feature" }
1818
rustc_hir = { path = "../librustc_hir" }
19+
rustc_mir = { path = "../librustc_mir" }
1920
rustc_index = { path = "../librustc_index" }
2021
rustc_session = { path = "../librustc_session" }
2122
rustc_target = { path = "../librustc_target" }

src/librustc_passes/check_const.rs

+44-9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_errors::struct_span_err;
1616
use rustc_hir as hir;
1717
use rustc_hir::def_id::DefId;
1818
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
19+
use rustc_mir::const_eval::is_min_const_fn;
1920
use rustc_span::{sym, Span, Symbol};
2021
use syntax::ast::Mutability;
2122

@@ -27,6 +28,8 @@ enum NonConstExpr {
2728
Loop(hir::LoopSource),
2829
Match(hir::MatchSource),
2930
OrPattern,
31+
LogicalOr,
32+
LogicalAnd,
3033
}
3134

3235
impl NonConstExpr {
@@ -35,6 +38,8 @@ impl NonConstExpr {
3538
Self::Loop(src) => format!("`{}`", src.name()),
3639
Self::Match(src) => format!("`{}`", src.name()),
3740
Self::OrPattern => format!("or-pattern"),
41+
Self::LogicalOr => format!("`||`"),
42+
Self::LogicalAnd => format!("`&&`"),
3843
}
3944
}
4045

@@ -46,6 +51,8 @@ impl NonConstExpr {
4651
Self::Match(Normal)
4752
| Self::Match(IfDesugar { .. })
4853
| Self::Match(IfLetDesugar { .. })
54+
| Self::LogicalOr
55+
| Self::LogicalAnd
4956
| Self::OrPattern => &[sym::const_if_match],
5057

5158
Self::Loop(Loop) => &[sym::const_loop],
@@ -64,26 +71,34 @@ impl NonConstExpr {
6471
}
6572
}
6673

67-
#[derive(Copy, Clone)]
74+
#[derive(Copy, Clone, PartialEq, Eq)]
6875
enum ConstKind {
6976
Static,
7077
StaticMut,
7178
ConstFn,
79+
MinConstFn,
7280
Const,
7381
AnonConst,
7482
}
7583

7684
impl ConstKind {
77-
fn for_body(body: &hir::Body<'_>, hir_map: Hir<'_>) -> Option<Self> {
78-
let is_const_fn = |id| hir_map.fn_sig_by_hir_id(id).unwrap().header.is_const();
79-
80-
let owner = hir_map.body_owner(body.id());
81-
let const_kind = match hir_map.body_owner_kind(owner) {
85+
fn for_body(tcx: TyCtxt<'_>, body: &hir::Body<'_>) -> Option<Self> {
86+
let owner = tcx.hir().body_owner(body.id());
87+
let const_kind = match tcx.hir().body_owner_kind(owner) {
8288
hir::BodyOwnerKind::Const => Self::Const,
8389
hir::BodyOwnerKind::Static(Mutability::Mut) => Self::StaticMut,
8490
hir::BodyOwnerKind::Static(Mutability::Not) => Self::Static,
8591

86-
hir::BodyOwnerKind::Fn if is_const_fn(owner) => Self::ConstFn,
92+
hir::BodyOwnerKind::Fn if is_min_const_fn(tcx, tcx.hir().local_def_id(owner)) => {
93+
Self::MinConstFn
94+
}
95+
96+
// Use `is_const_fn_raw` here since we need to check the bodies of unstable `const fn`
97+
// as well as stable ones.
98+
hir::BodyOwnerKind::Fn if tcx.is_const_fn_raw(tcx.hir().local_def_id(owner)) => {
99+
Self::ConstFn
100+
}
101+
87102
hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => return None,
88103
};
89104

@@ -97,7 +112,7 @@ impl fmt::Display for ConstKind {
97112
Self::Static => "static",
98113
Self::StaticMut => "static mut",
99114
Self::Const | Self::AnonConst => "const",
100-
Self::ConstFn => "const fn",
115+
Self::MinConstFn | Self::ConstFn => "const fn",
101116
};
102117

103118
write!(f, "{}", s)
@@ -211,7 +226,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
211226
}
212227

213228
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
214-
let kind = ConstKind::for_body(body, self.tcx.hir());
229+
let kind = ConstKind::for_body(self.tcx, body);
215230
self.recurse_into(kind, |this| intravisit::walk_body(this, body));
216231
}
217232

@@ -229,6 +244,26 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
229244
// Skip the following checks if we are not currently in a const context.
230245
_ if self.const_kind.is_none() => {}
231246

247+
// Short-circuiting operators were forbidden outright in the min_const_fn checks. In
248+
// other contexts, they are converted to non-short-circuiting operators while lowering
249+
// to MIR and marked as "control-flow destroyed". Bodies whose control-flow has been
250+
// altered in this manner are rejected during MIR const-checking if they have any
251+
// user-declared locals, since the user could observe the change like so:
252+
//
253+
// let mut altered_control_flow = false;
254+
// true && { altered_control_flow = true; false }
255+
hir::ExprKind::Binary(kind, _, _) if self.const_kind == Some(ConstKind::MinConstFn) => {
256+
let expr = match kind.node {
257+
hir::BinOpKind::And => Some(NonConstExpr::LogicalAnd),
258+
hir::BinOpKind::Or => Some(NonConstExpr::LogicalOr),
259+
_ => None,
260+
};
261+
262+
if let Some(expr) = expr {
263+
self.const_check_violated(expr, e.span);
264+
}
265+
}
266+
232267
hir::ExprKind::Loop(_, _, source) => {
233268
self.const_check_violated(NonConstExpr::Loop(*source), e.span);
234269
}

0 commit comments

Comments
 (0)