Skip to content

Commit 44a77f6

Browse files
committed
Auto merge of #32267 - durka:inclusive-range-error, r=nrc
melt the ICE when lowering an impossible range Emit a fatal error instead of panicking when HIR lowering encounters a range with no `end` point. This involved adding a method to wire up `LoweringContext::span_fatal`. Fixes #32245 (cc @nodakai). r? @nrc
2 parents 221c940 + 861644f commit 44a77f6

File tree

6 files changed

+88
-32
lines changed

6 files changed

+88
-32
lines changed

src/librustc/session/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ impl NodeIdAssigner for Session {
348348
fn peek_node_id(&self) -> NodeId {
349349
self.next_node_id.get().checked_add(1).unwrap()
350350
}
351+
352+
fn diagnostic(&self) -> &errors::Handler {
353+
self.diagnostic()
354+
}
351355
}
352356

353357
fn split_msg_into_multilines(msg: &str) -> Option<String> {

src/librustc_front/lowering.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ use std::collections::HashMap;
6868
use std::iter;
6969
use syntax::ast::*;
7070
use syntax::attr::{ThinAttributes, ThinAttributesExt};
71+
use syntax::errors::Handler;
7172
use syntax::ext::mtwt;
7273
use syntax::ptr::P;
7374
use syntax::codemap::{respan, Spanned, Span};
@@ -140,6 +141,11 @@ impl<'a, 'hir> LoweringContext<'a> {
140141
result
141142
}
142143
}
144+
145+
// Panics if this LoweringContext's NodeIdAssigner is not able to emit diagnostics.
146+
fn diagnostic(&self) -> &Handler {
147+
self.id_assigner.diagnostic()
148+
}
143149
}
144150

145151
// Utility fn for setting and unsetting the cached id.
@@ -1289,7 +1295,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
12891295
make_struct(lctx, e, &["RangeInclusive", "NonEmpty"],
12901296
&[("start", e1), ("end", e2)]),
12911297

1292-
_ => panic!("impossible range in AST"),
1298+
_ => panic!(lctx.diagnostic().span_fatal(e.span,
1299+
"inclusive range with no end"))
12931300
}
12941301
});
12951302
}

src/libsyntax/ast.rs

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use self::PathParameters::*;
1919
use attr::ThinAttributes;
2020
use codemap::{Span, Spanned, DUMMY_SP, ExpnId};
2121
use abi::Abi;
22+
use errors;
2223
use ext::base;
2324
use ext::tt::macro_parser;
2425
use parse::token::InternedString;
@@ -344,6 +345,10 @@ pub const DUMMY_NODE_ID: NodeId = !0;
344345
pub trait NodeIdAssigner {
345346
fn next_node_id(&self) -> NodeId;
346347
fn peek_node_id(&self) -> NodeId;
348+
349+
fn diagnostic(&self) -> &errors::Handler {
350+
panic!("this ID assigner cannot emit diagnostics")
351+
}
347352
}
348353

349354
/// The AST represents all type param bounds as types.

src/libsyntax/parse/parser.rs

+39-29
Original file line numberDiff line numberDiff line change
@@ -2072,8 +2072,15 @@ impl<'a> Parser<'a> {
20722072
start: Option<P<Expr>>,
20732073
end: Option<P<Expr>>,
20742074
limits: RangeLimits)
2075-
-> ast::ExprKind {
2076-
ExprKind::Range(start, end, limits)
2075+
-> PResult<'a, ast::ExprKind> {
2076+
if end.is_none() && limits == RangeLimits::Closed {
2077+
Err(self.span_fatal_help(self.span,
2078+
"inclusive range with no end",
2079+
"inclusive ranges must be bounded at the end \
2080+
(`...b` or `a...b`)"))
2081+
} else {
2082+
Ok(ExprKind::Range(start, end, limits))
2083+
}
20772084
}
20782085

20792086
pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::ExprKind {
@@ -2999,12 +3006,12 @@ impl<'a> Parser<'a> {
29993006
lhs = self.mk_expr(lhs_span.lo, rhs.span.hi,
30003007
ExprKind::Type(lhs, rhs), None);
30013008
continue
3002-
} else if op == AssocOp::DotDot {
3003-
// If we didn’t have to handle `x..`, it would be pretty easy to generalise
3004-
// it to the Fixity::None code.
3009+
} else if op == AssocOp::DotDot || op == AssocOp::DotDotDot {
3010+
// If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
3011+
// generalise it to the Fixity::None code.
30053012
//
3006-
// We have 2 alternatives here: `x..y` and `x..` The other two variants are
3007-
// handled with `parse_prefix_range_expr` call above.
3013+
// We have 2 alternatives here: `x..y`/`x...y` and `x..`/`x...` The other
3014+
// two variants are handled with `parse_prefix_range_expr` call above.
30083015
let rhs = if self.is_at_start_of_range_notation_rhs() {
30093016
let rhs = self.parse_assoc_expr_with(op.precedence() + 1,
30103017
LhsExpr::NotYetParsed);
@@ -3023,7 +3030,13 @@ impl<'a> Parser<'a> {
30233030
} else {
30243031
cur_op_span
30253032
});
3026-
let r = self.mk_range(Some(lhs), rhs, RangeLimits::HalfOpen);
3033+
let limits = if op == AssocOp::DotDot {
3034+
RangeLimits::HalfOpen
3035+
} else {
3036+
RangeLimits::Closed
3037+
};
3038+
3039+
let r = try!(self.mk_range(Some(lhs), rhs, limits));
30273040
lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
30283041
break
30293042
}
@@ -3041,8 +3054,8 @@ impl<'a> Parser<'a> {
30413054
this.parse_assoc_expr_with(op.precedence() + 1,
30423055
LhsExpr::NotYetParsed)
30433056
}),
3044-
// the only operator handled here is `...` (the other non-associative operators are
3045-
// special-cased above)
3057+
// We currently have no non-associative operators that are not handled above by
3058+
// the special cases. The code is here only for future convenience.
30463059
Fixity::None => self.with_res(
30473060
restrictions - Restrictions::RESTRICTION_STMT_EXPR,
30483061
|this| {
@@ -3083,13 +3096,8 @@ impl<'a> Parser<'a> {
30833096
let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
30843097
self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None)
30853098
}
3086-
AssocOp::DotDotDot => {
3087-
let (lhs_span, rhs_span) = (lhs.span, rhs.span);
3088-
let r = self.mk_range(Some(lhs), Some(rhs), RangeLimits::Closed);
3089-
self.mk_expr(lhs_span.lo, rhs_span.hi, r, None)
3090-
}
3091-
AssocOp::As | AssocOp::Colon | AssocOp::DotDot => {
3092-
self.bug("As, Colon or DotDot branch reached")
3099+
AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => {
3100+
self.bug("As, Colon, DotDot or DotDotDot branch reached")
30933101
}
30943102
};
30953103

@@ -3133,21 +3141,23 @@ impl<'a> Parser<'a> {
31333141
// RHS must be parsed with more associativity than the dots.
31343142
let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1;
31353143
Some(self.parse_assoc_expr_with(next_prec,
3136-
LhsExpr::NotYetParsed)
3137-
.map(|x|{
3138-
hi = x.span.hi;
3139-
x
3140-
})?)
3144+
LhsExpr::NotYetParsed)
3145+
.map(|x|{
3146+
hi = x.span.hi;
3147+
x
3148+
})?)
31413149
} else {
31423150
None
31433151
};
3144-
let r = self.mk_range(None,
3145-
opt_end,
3146-
if tok == token::DotDot {
3147-
RangeLimits::HalfOpen
3148-
} else {
3149-
RangeLimits::Closed
3150-
});
3152+
let limits = if tok == token::DotDot {
3153+
RangeLimits::HalfOpen
3154+
} else {
3155+
RangeLimits::Closed
3156+
};
3157+
3158+
let r = try!(self.mk_range(None,
3159+
opt_end,
3160+
limits));
31513161
Ok(self.mk_expr(lo, hi, r, attrs))
31523162
}
31533163

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Make sure that invalid ranges generate an error during HIR lowering, not an ICE
12+
13+
#![feature(inclusive_range_syntax)]
14+
15+
pub fn main() {
16+
..;
17+
0..;
18+
..1;
19+
0..1;
20+
21+
...; //~ERROR inclusive range with no end
22+
//~^HELP bounded at the end
23+
0...; //~ERROR inclusive range with no end
24+
//~^HELP bounded at the end
25+
...1;
26+
0...1;
27+
}
28+
29+

src/test/parse-fail/range_inclusive.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![feature(inclusive_range_syntax, inclusive_range)]
1414

1515
pub fn main() {
16-
for _ in 1... {}
17-
} //~ ERROR expected one of
16+
for _ in 1... {} //~ERROR inclusive range with no end
17+
//~^HELP bounded at the end
18+
}
1819

0 commit comments

Comments
 (0)