Skip to content

Commit ccb6e98

Browse files
Suggest const_if_match on nightly
1 parent f4b9dc7 commit ccb6e98

File tree

1 file changed

+70
-19
lines changed

1 file changed

+70
-19
lines changed

src/librustc_passes/check_const.rs

+70-19
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,43 @@ use rustc::hir;
1414
use rustc::ty::TyCtxt;
1515
use rustc::ty::query::Providers;
1616
use syntax::ast::Mutability;
17+
use syntax::feature_gate::{emit_feature_err, Features, GateIssue};
1718
use syntax::span_err;
18-
use syntax_pos::Span;
19+
use syntax_pos::{sym, Span};
1920
use rustc_error_codes::*;
2021

2122
use std::fmt;
2223

24+
/// An expression that is not *always* legal in a const context.
25+
#[derive(Clone, Copy)]
26+
enum NonConstExpr {
27+
Loop(hir::LoopSource),
28+
Match(hir::MatchSource),
29+
}
30+
31+
impl NonConstExpr {
32+
fn name(self) -> &'static str {
33+
match self {
34+
Self::Loop(src) => src.name(),
35+
Self::Match(src) => src.name(),
36+
}
37+
}
38+
39+
/// Returns `true` if all feature gates required to enable this expression are turned on, or
40+
/// `None` if there is no feature gate corresponding to this expression.
41+
fn is_feature_gate_enabled(self, features: &Features) -> Option<bool> {
42+
use hir::MatchSource::*;
43+
match self {
44+
| Self::Match(Normal)
45+
| Self::Match(IfDesugar { .. })
46+
| Self::Match(IfLetDesugar { .. })
47+
=> Some(features.const_if_match),
48+
49+
_ => None,
50+
}
51+
}
52+
}
53+
2354
#[derive(Copy, Clone)]
2455
enum ConstKind {
2556
Static,
@@ -87,16 +118,38 @@ impl<'tcx> CheckConstVisitor<'tcx> {
87118
}
88119

89120
/// Emits an error when an unsupported expression is found in a const context.
90-
fn const_check_violated(&self, bad_op: &str, span: Span) {
91-
if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
92-
self.tcx.sess.span_warn(span, "skipping const checks");
93-
return;
121+
fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
122+
match expr.is_feature_gate_enabled(self.tcx.features()) {
123+
// Don't emit an error if the user has enabled the requisite feature gates.
124+
Some(true) => return,
125+
126+
// Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible.
127+
None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
128+
self.tcx.sess.span_warn(span, "skipping const checks");
129+
return;
130+
}
131+
132+
_ => {}
94133
}
95134

96135
let const_kind = self.const_kind
97136
.expect("`const_check_violated` may only be called inside a const context");
98137

99-
span_err!(self.tcx.sess, span, E0744, "`{}` is not allowed in a `{}`", bad_op, const_kind);
138+
let msg = format!("`{}` is not allowed in a `{}`", expr.name(), const_kind);
139+
match expr {
140+
| NonConstExpr::Match(hir::MatchSource::Normal)
141+
| NonConstExpr::Match(hir::MatchSource::IfDesugar { .. })
142+
| NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. })
143+
=> emit_feature_err(
144+
&self.tcx.sess.parse_sess,
145+
sym::const_if_match,
146+
span,
147+
GateIssue::Language,
148+
&msg
149+
),
150+
151+
_ => span_err!(self.tcx.sess, span, E0744, "{}", msg),
152+
}
100153
}
101154

102155
/// Saves the parent `const_kind` before calling `f` and restores it afterwards.
@@ -129,24 +182,22 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
129182
_ if self.const_kind.is_none() => {}
130183

131184
hir::ExprKind::Loop(_, _, source) => {
132-
self.const_check_violated(source.name(), e.span);
185+
self.const_check_violated(NonConstExpr::Loop(*source), e.span);
133186
}
134187

135-
hir::ExprKind::Match(_, _, source) if !self.tcx.features().const_if_match => {
136-
use hir::MatchSource::*;
137-
138-
let op = match source {
139-
Normal => Some("match"),
140-
IfDesugar { .. } | IfLetDesugar { .. } => Some("if"),
141-
TryDesugar => Some("?"),
142-
AwaitDesugar => Some(".await"),
143-
188+
hir::ExprKind::Match(_, _, source) => {
189+
let non_const_expr = match source {
144190
// These are handled by `ExprKind::Loop` above.
145-
WhileDesugar | WhileLetDesugar | ForLoopDesugar => None,
191+
| hir::MatchSource::WhileDesugar
192+
| hir::MatchSource::WhileLetDesugar
193+
| hir::MatchSource::ForLoopDesugar
194+
=> None,
195+
196+
_ => Some(NonConstExpr::Match(*source)),
146197
};
147198

148-
if let Some(op) = op {
149-
self.const_check_violated(op, e.span);
199+
if let Some(expr) = non_const_expr {
200+
self.const_check_violated(expr, e.span);
150201
}
151202
}
152203

0 commit comments

Comments
 (0)