-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
segfault in panic=abort mode #62
Comments
gdb backtrace:
|
valgrind output:
|
My guess is that this is a bug in rustc. It's interesting to note that the control flow where the error happens is similar to the control flow in a previous bug. |
Whew! Any suggestions on how to minimize this in order to get something submittable as a bug report? |
I wish I had a way to automate the minimization! I've started an attempt to manually minimize the code... |
Here's a smaller more self-contained program that segfaults using the latest nightly # Cargo.toml
[package]
authors = ["David Renshaw <[email protected]>"]
name = "fuzzy-pickles-test"
version = "0.0.2"
[dependencies.peresil]
git = "https://github.com/shepmaster/peresil"
features = ["combinators"]
[[bin]]
name = "parse"
path = "parse.rs"
[profile.release]
panic = "abort" parse.rs// parse.rs
#![feature(conservative_impl_trait)]
#[macro_use]
extern crate peresil;
use std::fmt;
use peresil::combinators::*;
type Point<'s> = TokenPoint<'s, Token>;
type Master<'s> = peresil::ParseMaster<Point<'s>, Error, State<'s>>;
type Progress<'s, T> = peresil::Progress<Point<'s>, T, Error>;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Token {
AmpersandEquals(Extent),
Ident(Extent),
EndOfFile(Extent),
}
impl Token {
fn extent(&self) -> Extent {
use self::Token::*;
match *self {
AmpersandEquals(s) | EndOfFile(s) | Ident(s) => s,
}
}
fn into_double_colon1(self) -> Option<Extent> { None }
fn into_ident1(self) -> Option<Extent> {
match self {
Token::Ident(s) => Some(s),
_ => None,
}
}
fn into_ampersand_equals1(self) -> Option<Extent> {
match self {
Token::AmpersandEquals(s) => Some(s),
_ => None,
}
}
}
fn main() {
let _ = parse_rust_file();
}
#[derive(Debug)]
struct TokenPoint<'s, T: 's> {
pub offset: usize,
pub sub_offset: Option<u8>,
pub s: &'s [T],
}
impl<'s, T: 's> TokenPoint<'s, T> {
fn new(slice: &'s [T]) -> Self {
TokenPoint {
offset: 0,
sub_offset: None,
s: slice,
}
}
fn advance_by(&self, offset: usize) -> Self {
TokenPoint {
offset: self.offset + offset,
sub_offset: None,
s: &self.s[offset..],
}
}
fn location(&self) -> (usize, Option<u8>) {
(self.offset, self.sub_offset)
}
}
impl<'s, T> peresil::Point for TokenPoint<'s, T> {
fn zero() -> Self {
Self::new(&[])
}
}
impl<'s, T> Copy for TokenPoint<'s, T> {}
impl<'s, T> Clone for TokenPoint<'s, T> {
fn clone(&self) -> Self { *self }
}
impl<'s, T> PartialOrd for TokenPoint<'s, T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'s, T> Ord for TokenPoint<'s, T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.location().cmp(&other.location())
}
}
impl<'s, T> PartialEq for TokenPoint<'s, T> {
fn eq(&self, other: &Self) -> bool {
self.location().eq(&other.location())
}
}
impl<'s, T> Eq for TokenPoint<'s, T> {}
// -----
#[derive(Debug, Default)]
struct State<'s> {
ignore_struct_literals: bool,
tokens: &'s [Token],
}
impl<'s> State<'s> {
#[allow(dead_code)]
fn new(tokens: &'s [Token]) -> Self {
State {
tokens,
..State::default()
}
}
fn ex(&self, start: Point, end: Point) -> Extent {
if end.offset > start.offset {
let (a, _) = self.tokens[start.offset].extent();
let (_, b) = self.tokens[end.offset-1].extent();
(a, b)
} else {
self.tokens[start.offset].extent()
}
}
}
// define an error type - emphasis on errors. Need to implement Recoverable (more to discuss.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Error {
ExpectedAmpersandEquals,
ExpectedDoubleColon,
ExpectedIdent,
ExpectedExpression,
}
impl peresil::Recoverable for Error {
fn recoverable(&self) -> bool { true }
}
#[derive(Debug, PartialEq)]
pub enum ErrorDetail {
Tokenizer,
Parser(ParserErrorDetail),
}
impl From<ParserErrorDetail> for ErrorDetail {
fn from(other: ParserErrorDetail) -> Self {
ErrorDetail::Parser(other)
}
}
#[derive(Debug)]
pub struct ErrorDetailText<'a> {
detail: &'a ErrorDetail,
text: &'a str,
}
impl<'a> fmt::Display for ErrorDetailText<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub struct ParserErrorDetail {
location: usize,
}
impl ParserErrorDetail {
pub fn with_text<'a>(&'a self, text: &'a str) -> ParserErrorDetailText<'a> {
ParserErrorDetailText { detail: self, text }
}
}
#[derive(Debug)]
pub struct ParserErrorDetailText<'a> {
detail: &'a ParserErrorDetail,
text: &'a str,
}
impl<'a> fmt::Display for ParserErrorDetailText<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Ok(()) }
}
pub fn parse_rust_file() -> Result<(), ErrorDetail> {
let tokens = &[Token::Ident((0,1)), Token::AmpersandEquals((1,3)), Token::Ident((3,4)),
Token::EndOfFile((4,4))];
println!("tokens {:?}", tokens);
let pt = Point::new(tokens);
let mut pm = Master::with_state(State::new(tokens));
let _ = expression(&mut pm, pt);
Ok(())
}
// TODO: enum variants track whole extent, enum delegates
pub type Extent = (usize, usize);
#[derive(Debug, Copy, Clone)]
pub struct Ident {
pub extent: Extent,
}
#[derive(Debug)]
pub struct Path {
extent: Extent,
components: Vec<Ident>,
}
#[derive(Debug)]
pub struct PathedIdent {
extent: Extent,
components: Vec<PathComponent>,
}
#[derive(Debug)]
struct PathComponent {
extent: Extent,
ident: Ident,
}
impl From<Ident> for PathedIdent {
fn from(other: Ident) -> PathedIdent {
PathedIdent { extent: other.extent, components: vec![
PathComponent { extent: other.extent, ident: other, },
] }
}
}
#[derive(Debug)]
enum Expression {
AsType(AsType),
Binary(Binary),
Call(Call),
FieldAccess(FieldAccess),
Slice(Slice),
Value(Value),
}
#[derive(Debug)]
struct FieldAccess {
extent: Extent,
target: Box<Expression>,
}
#[derive(Debug)]
pub struct Value {
extent: Extent,
name: PathedIdent,
}
#[derive(Debug)]
pub struct Call {
extent: Extent,
target: Box<Expression>,
args: Vec<Expression>,
}
#[derive(Debug)]
pub struct Binary {
extent: Extent,
op: BinaryOp,
lhs: Box<Expression>,
rhs: Box<Expression>,
}
#[derive(Debug)]
pub enum BinaryOp {
BitwiseAndAssign,
}
#[derive(Debug)]
struct AsType {
extent: Extent,
target: Box<Expression>,
}
#[derive(Debug)]
struct Slice {
extent: Extent,
target: Box<Expression>,
index: Box<Expression>,
}
// --------------------------------------------------
enum TailedState<P, T, E> {
Nothing(P, E),
ValueOnly(P, T),
}
fn parse_tailed<'s, F, S, T, U>(sep: S, f: F, pm: &mut Master<'s>, pt: Point<'s>) ->
TailedState<Point<'s>, T, Error>
where S: Fn(&mut Master<'s>, Point<'s>) -> Progress<'s, U>,
F: Fn(&mut Master<'s>, Point<'s>) -> Progress<'s, T>,
{
match f(pm, pt) {
Progress { status: peresil::Status::Failure(f), point } => {
TailedState::Nothing(point, f)
}
Progress { status: peresil::Status::Success(value), point } => {
match sep(pm, point) {
Progress { status: peresil::Status::Failure(_), point } => {
TailedState::ValueOnly(point, value)
}
Progress { status: peresil::Status::Success(_), .. } => {
unimplemented!()
}
}
}
}
}
#[derive(Debug)]
struct Tailed<T> {
values: Vec<T>,
separator_count: usize,
last_had_separator: bool,
}
impl<T> Default for Tailed<T> {
fn default() -> Self {
Tailed {
values: Vec::new(),
separator_count: 0,
last_had_separator: false,
}
}
}
fn one_or_more_tailed<'s, S, F, T, U>(sep: S, f: F) ->
impl FnOnce(&mut Master<'s>, Point<'s>) -> Progress<'s, Tailed<T>>
where S: Fn(&mut Master<'s>, Point<'s>) -> Progress<'s, U>,
F: Fn(&mut Master<'s>, Point<'s>) -> Progress<'s, T>
{
move |pm, pt| {
let mut tailed = Tailed::default();
match parse_tailed(&sep, &f, pm, pt) {
TailedState::Nothing(pt, f) => {
return Progress::failure(pt, f);
}
TailedState::ValueOnly(pt, v) => {
tailed.values.push(v);
return Progress::success(pt, tailed);
}
}
}
}
fn one_or_more_tailed_values<'s, S, F, T, U>(sep: S, f: F) ->
impl FnOnce(&mut Master<'s>, Point<'s>) -> Progress<'s, Vec<T>>
where S: Fn(&mut Master<'s>, Point<'s>) -> Progress<'s, U>,
F: Fn(&mut Master<'s>, Point<'s>) -> Progress<'s, T>
{
map(one_or_more_tailed(sep, f), |t| t.values)
}
// --------------------------------------------------
macro_rules! shim {
($name:ident, $matcher:expr, $error:expr) => {
shim!($name, $matcher, $error, Extent);
};
($name:ident, $matcher:expr, $error:expr, $t:ty) => {
fn $name<'s>(pm: &mut Master<'s>, pt: Point<'s>) -> Progress<'s, $t> {
token($matcher, $error)(pm, pt)
}
};
}
shim!(ident_normal, Token::into_ident1, Error::ExpectedIdent);
shim!(ampersand_equals, Token::into_ampersand_equals1, Error::ExpectedAmpersandEquals);
shim!(double_colon, Token::into_double_colon1, Error::ExpectedDoubleColon);
fn token<'s, F, T>(token_convert: F, error: Error) ->
impl FnOnce(&mut Master<'s>, Point<'s>) -> Progress<'s, T>
where F: Fn(Token) -> Option<T>
{
move |_, pt| {
let original_token = match pt.s.first() {
Some(&token) => token,
None => return Progress::failure(pt, error),
};
match token_convert(original_token) {
Some(v) => {
// We exactly matched the requested token
Progress::success(pt.advance_by(1), v)
}
None => {
Progress::failure(pt, error)
}
}
}
}
fn ident<'s>(pm: &mut Master<'s>, pt: Point<'s>) -> Progress<'s, Ident> {
pm.alternate(pt)
.one(ident_normal)
.finish()
.map(|extent| Ident { extent })
.map_err(|_| Error::ExpectedIdent)
}
#[derive(Debug)]
enum OperatorInfix {
BitwiseAndAssign(Extent),
}
#[derive(Debug)]
enum OperatorPostfix {
AsType { typ: () },
Call { args: Vec<Expression> },
FieldAccess { field: () },
Slice { index: Expression },
}
#[derive(Debug)]
enum OperatorKind {
Infix(OperatorInfix),
Postfix(OperatorPostfix),
}
type Precedence = u8;
impl OperatorKind {
fn precedence(&self) -> Precedence {
use OperatorKind::*;
match *self {
Infix(_) => 10,
Postfix(OperatorPostfix::Call { .. }) => 10,
Postfix(_) => 20,
}
}
}
#[derive(Debug)]
enum PrefixOrAtom {
Atom(Expression),
}
#[derive(Debug)]
enum InfixOrPostfix {
Infix(OperatorInfix),
Postfix(OperatorPostfix),
}
fn expression_prefix_or_atom<'s>(pm: &mut Master<'s>, pt: Point<'s>) ->
Progress<'s, PrefixOrAtom>
{
pm.alternate(pt)
.one(map(expression_atom, PrefixOrAtom::Atom))
.finish()
}
fn expression_infix_or_postfix<'s>(pm: &mut Master<'s>, pt: Point<'s>) ->
Progress<'s, InfixOrPostfix>
{
pm.alternate(pt)
.one(map(operator_infix, InfixOrPostfix::Infix))
.finish()
}
fn operator_infix<'s>(pm: &mut Master<'s>, pt: Point<'s>) ->
Progress<'s, OperatorInfix>
{
pm.alternate(pt)
.one(map(ampersand_equals, OperatorInfix::BitwiseAndAssign))
.finish()
}
fn expression_atom<'s>(pm: &mut Master<'s>, pt: Point<'s>) -> Progress<'s, Expression> {
pm.alternate(pt)
.one(map(expr_value, Expression::Value))
.finish()
}
struct ShuntCar<'s, T> {
value: T,
spt: Point<'s>,
ept: Point<'s>,
}
struct ShuntingYard<'s> {
operators: Vec<ShuntCar<'s, OperatorKind>>,
result: Vec<ShuntCar<'s, Expression>>,
}
type PointRange<'s> = std::ops::Range<Point<'s>>;
type ExprResult<'s, T> = std::result::Result<T, (Point<'s>, Error)>;
impl<'s> ShuntingYard<'s> {
fn new() -> Self {
ShuntingYard {
operators: Vec::new(),
result: Vec::new(),
}
}
fn add_expression(&mut self, expr: Expression, spt: Point<'s>, ept: Point<'s>) {
self.result.push(ShuntCar { value: expr, spt, ept });
}
fn add_infix(&mut self, pm: &Master, op: OperatorInfix, spt: Point<'s>, ept: Point<'s>) ->
ExprResult<'s, ()>
{
let op = OperatorKind::Infix(op);
self.apply_precedence(pm, &op)?;
self.operators.push(ShuntCar { value: op, spt, ept });
Ok(())
}
fn finish(mut self, pm: &Master, failure_point: Point<'s>) ->
ExprResult<'s, ShuntCar<'s, Expression>>
{
self.apply_all(pm)?;
let r = self.pop_expression(failure_point);
assert_eq!(0, self.result.len());
r
}
fn apply_precedence(&mut self, pm: &Master, operator: &OperatorKind) -> ExprResult<'s, ()> {
let op_precedence = operator.precedence();
while self.operators.last().map_or(false, |&ShuntCar { value: ref top, .. }| top.precedence() > op_precedence) {
let ShuntCar { value, spt, ept } = self.operators.pop()
.expect("Cannot pop operator that was just there");
self.apply_one(pm, value, spt..ept)?;
}
Ok(())
}
fn apply_all(&mut self, pm: &Master) -> ExprResult<'s, ()> {
while let Some(ShuntCar { value, spt, ept }) = self.operators.pop() {
self.apply_one(pm, value, spt..ept)?;
}
Ok(())
}
fn apply_one(&mut self, pm: &Master, op: OperatorKind, op_range: PointRange<'s>) ->
ExprResult<'s, ()>
{
use OperatorKind::*;
match op {
Infix(OperatorInfix::BitwiseAndAssign(..)) => self.apply_binary(pm, op_range, BinaryOp::BitwiseAndAssign),
Postfix(OperatorPostfix::FieldAccess { .. }) => unimplemented!(),
Postfix(OperatorPostfix::Call { args }) => unimplemented!(),
Postfix(OperatorPostfix::Slice { .. }) => unimplemented!(),
Postfix(OperatorPostfix::AsType { .. }) => unimplemented!(),
}
}
fn apply_infix<F>(&mut self, pm: &Master, op_range: PointRange<'s>, f: F) ->
ExprResult<'s, ()>
where F: FnOnce(Extent, Expression, Expression) -> Expression
{
let ShuntCar { value: rhs, ept: rexpr_ept, .. } = self.pop_expression(op_range.end)?;
let ShuntCar { value: lhs, spt: lexpr_spt, .. } = self.pop_expression(op_range.start)?;
let extent = pm.state.ex(lexpr_spt, rexpr_ept);
let new_expr = f(extent, lhs, rhs);
self.result.push(ShuntCar { value: new_expr, spt: lexpr_spt, ept: rexpr_ept });
Ok(())
}
fn apply_binary(&mut self, pm: &Master, op_range: PointRange<'s>, op: BinaryOp) ->
ExprResult<'s, ()>
{
self.apply_infix(pm, op_range, |extent, lhs, rhs| {
Expression::Binary(Binary {
extent,
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
})
})
}
fn pop_expression(&mut self, location: Point<'s>) ->
ExprResult<'s, ShuntCar<'s, Expression>>
{
self.result.pop().ok_or((location, Error::ExpectedExpression))
}
}
#[derive(Debug, Copy, Clone)]
enum ExpressionState {
Prefix, // Also "beginning of expression"
Infix,
Postfix,
Atom,
}
fn expression<'s>(pm: &mut Master<'s>, pt: Point<'s>) -> Progress<'s, Expression> {
match expression_x(pm, pt) {
Ok(ShuntCar { value: expr, ept, .. }) => Progress::success(ept, expr),
Err((failure_point, err)) => Progress::failure(failure_point, err),
}
}
fn expression_x<'s>(pm: &mut Master<'s>, mut pt: Point<'s>) ->
ExprResult<'s, ShuntCar<'s, Expression>>
{
let mut shunting_yard = ShuntingYard::new();
let mut state = ExpressionState::Prefix;
println!("expression_x");
loop {
println!("expression_x loop");
match state {
ExpressionState::Prefix |
ExpressionState::Infix => {
println!("branch 1");
match expression_prefix_or_atom(pm, pt) {
peresil::Progress { status: peresil::Status::Success(op_or_atom), point } => {
match op_or_atom {
PrefixOrAtom::Atom(expr) => {
shunting_yard.add_expression(expr, pt, point);
state = ExpressionState::Atom;
}
}
pt = point;
}
peresil::Progress { status: peresil::Status::Failure(_), .. } => {
unimplemented!()
}
}
}
ExpressionState::Postfix |
ExpressionState::Atom => {
println!("branch 2");
match expression_infix_or_postfix(pm, pt) {
peresil::Progress { status: peresil::Status::Success(infix_or_postfix), point } => {
match infix_or_postfix {
InfixOrPostfix::Infix(op) => {
shunting_yard.add_infix(pm, op, pt, point)?;
state = ExpressionState::Infix;
}
InfixOrPostfix::Postfix(_) => unimplemented!(),
}
pt = point;
}
peresil::Progress { status: peresil::Status::Failure(_), point } => {
return shunting_yard.finish(pm, point);
}
}
}
}
}
}
fn expr_value<'s>(pm: &mut Master<'s>, pt: Point<'s>) -> Progress<'s, Value> {
if pm.state.ignore_struct_literals {
sequence!(pm, pt, {
spt = point;
name = pathed_ident;
}, |pm: &mut Master, pt| Value { extent: pm.state.ex(spt, pt), name })
} else {
sequence!(pm, pt, {
spt = point;
name = pathed_ident;
}, |pm: &mut Master, pt| Value { extent: pm.state.ex(spt, pt), name })
}
}
fn pathed_ident<'s>(pm: &mut Master<'s>, pt: Point<'s>) -> Progress<'s, PathedIdent> {
sequence!(pm, pt, {
spt = point;
components = one_or_more_tailed_values(double_colon, path_component);
}, |pm: &mut Master, pt| PathedIdent { extent: pm.state.ex(spt, pt), components })
}
fn path_component<'s>(pm: &mut Master<'s>, pt: Point<'s>) -> Progress<'s, PathComponent> {
sequence!(pm, pt, {
spt = point;
ident = ident;
}, |pm: &mut Master, pt| PathComponent { extent: pm.state.ex(spt, pt), ident })
} |
Here's a smaller version without any dependencies. It segfaults on beta and nightly but not on stable: # Cargo.toml
[package]
authors = ["David Renshaw <[email protected]>"]
name = "fuzzy-pickles-test"
version = "0.0.3"
[[bin]]
name = "parse"
path = "parse.rs"
[profile.release]
panic = "abort" // parse.rs
fn main() {
let tokens = &[Token::Ident, Token::AmpersandEquals, Token::Ident];
let _ = expression(Point::new(tokens));
}
struct Progress<'s, T> {
point: Point<'s>,
status: Result<T, ()>,
}
impl<'s, T> Progress<'s, T> {
pub fn success(point: Point<'s>, val: T) -> Self {
Progress { point: point, status: Ok(val) }
}
pub fn failure(point: Point<'s>) -> Self {
Progress { point: point, status: Err(()) }
}
pub fn map<F, T2>(self, f: F) -> Progress<'s, T2>
where F: FnOnce(T) -> T2
{
Progress { point: self.point, status: self.status.map(f) }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Token {
AmpersandEquals,
Ident,
}
impl Token {
fn into_ident(self) -> Option<Extent> {
match self {
Token::Ident => Some((0,0)),
_ => None,
}
}
fn into_ampersand_equals(self) -> Option<Extent> {
match self {
Token::AmpersandEquals => Some((0,0)),
_ => None,
}
}
}
#[derive(Copy, Clone)]
struct Point<'s> {
pub offset: usize,
pub sub_offset: Option<u8>,
pub s: &'s [Token],
}
impl<'s> Point<'s> {
fn new(slice: &'s [Token]) -> Self {
Point {
offset: 0,
sub_offset: None,
s: slice,
}
}
fn advance_by(&self, offset: usize) -> Self {
Point {
offset: self.offset + offset,
sub_offset: None,
s: &self.s[offset..],
}
}
}
pub type Extent = (usize, usize);
enum Expression {
AsType(AsType),
Binary(Binary),
Call(Call),
FieldAccess(FieldAccess),
Slice(Slice),
Value(Value),
}
struct FieldAccess {
target: Box<Expression>,
}
pub struct Value;
pub struct Call {
extent: Extent,
target: Box<Expression>,
args: Vec<Expression>,
}
pub struct Binary {
lhs: Box<Expression>,
rhs: Box<Expression>,
}
struct AsType {
extent: Extent,
target: Box<Expression>,
}
struct Slice {
target: Box<Expression>,
index: Box<Expression>,
}
fn token<'s, F, T>(token_convert: F, pt: Point<'s>) ->
Progress<'s, T>
where F: Fn(Token) -> Option<T>,
{
let original_token = match pt.s.first() {
Some(&token) => token,
None => return Progress::failure(pt),
};
match token_convert(original_token) {
Some(v) => {
Progress::success(pt.advance_by(1), v)
}
None => {
Progress::failure(pt)
}
}
}
enum OperatorInfix {
BitwiseAndAssign(Extent),
}
enum OperatorPostfix {
AsType { typ: () },
Call { args: Vec<Expression> },
FieldAccess { field: () },
Slice { index: Expression },
}
enum OperatorKind {
Infix(OperatorInfix),
Postfix(OperatorPostfix),
}
impl OperatorKind {
fn precedence(&self) -> u8 {
match *self {
OperatorKind::Infix(_) => 10,
OperatorKind::Postfix(OperatorPostfix::Call { .. }) => 10,
OperatorKind::Postfix(_) => 20,
}
}
}
enum InfixOrPostfix {
Infix(OperatorInfix),
Postfix(OperatorPostfix),
}
struct ShuntCar<'s, T> {
value: T,
spt: Point<'s>,
ept: Point<'s>,
}
struct ShuntingYard<'s> {
operators: Vec<ShuntCar<'s, OperatorKind>>,
result: Vec<ShuntCar<'s, Expression>>,
}
type PointRange<'s> = std::ops::Range<Point<'s>>;
type ExprResult<'s, T> = std::result::Result<T, Point<'s>>;
impl<'s> ShuntingYard<'s> {
fn new() -> Self {
ShuntingYard {
operators: Vec::new(),
result: Vec::new(),
}
}
fn add_infix(&mut self, op: OperatorInfix, spt: Point<'s>, ept: Point<'s>) -> ExprResult<'s, ()>
{
let op = OperatorKind::Infix(op);
self.apply_precedence(&op)?;
self.operators.push(ShuntCar { value: op, spt, ept });
Ok(())
}
fn finish(mut self, failure_point: Point<'s>) -> ExprResult<'s, ShuntCar<'s, Expression>>
{
self.apply_all()?;
self.pop_expression(failure_point)
}
fn apply_precedence(&mut self, operator: &OperatorKind) -> ExprResult<'s, ()> {
let op_precedence = operator.precedence();
while self.operators.last().map_or(false, |&ShuntCar { value: ref top, .. }| top.precedence() > op_precedence) {
let ShuntCar { value: _, spt, ept } = self.operators.pop().unwrap();
self.apply_one(spt..ept)?;
}
Ok(())
}
fn apply_all(&mut self) -> ExprResult<'s, ()> {
while let Some(ShuntCar { value: _, spt, ept }) = self.operators.pop() {
self.apply_one(spt..ept)?;
}
Ok(())
}
fn apply_one(&mut self, op_range: PointRange<'s>) -> ExprResult<'s, ()>
{
self.apply_binary(op_range)
}
fn apply_infix<F>(&mut self, op_range: PointRange<'s>, f: F) ->
ExprResult<'s, ()>
where F: FnOnce(Expression, Expression) -> Expression
{
let ShuntCar { value: rhs, ept: rexpr_ept, .. } = self.pop_expression(op_range.end)?;
let ShuntCar { value: lhs, spt: lexpr_spt, .. } = self.pop_expression(op_range.start)?;
let new_expr = f(lhs, rhs);
self.result.push(ShuntCar { value: new_expr, spt: lexpr_spt, ept: rexpr_ept });
Ok(())
}
fn apply_binary(&mut self, op_range: PointRange<'s>) ->
ExprResult<'s, ()>
{
self.apply_infix(op_range, |lhs, rhs| {
Expression::Binary(Binary {
lhs: Box::new(lhs),
rhs: Box::new(rhs),
})
})
}
fn pop_expression(&mut self, location: Point<'s>) ->
ExprResult<'s, ShuntCar<'s, Expression>>
{
self.result.pop().ok_or(location)
}
}
enum ExpressionState {
Prefix, // Also "beginning of expression"
Infix,
Atom,
}
fn expression<'s>(pt: Point<'s>) -> Progress<'s, Expression> {
match expression_x(pt) {
Ok(ShuntCar { value: expr, ept, .. }) => Progress::success(ept, expr),
Err(failure_point) => Progress::failure(failure_point),
}
}
fn expression_x<'s>(mut pt: Point<'s>) ->
ExprResult<'s, ShuntCar<'s, Expression>>
{
let mut shunting_yard = ShuntingYard::new();
let mut state = ExpressionState::Prefix;
loop {
println!("expression_x loop");
match state {
ExpressionState::Prefix |
ExpressionState::Infix => {
println!("branch 1");
let Progress { point, .. } =
token(Token::into_ident, pt).map(|_| Value).map(Expression::Value);
state = ExpressionState::Atom;
pt = point;
}
ExpressionState::Atom => {
println!("branch 2");
match token(Token::into_ampersand_equals, pt)
.map(OperatorInfix::BitwiseAndAssign).map(InfixOrPostfix::Infix) {
Progress { status: Ok(infix_or_postfix), point } => {
match infix_or_postfix {
InfixOrPostfix::Infix(op) => {
shunting_yard.add_infix(op, pt, point)?;
state = ExpressionState::Infix;
}
InfixOrPostfix::Postfix(_) => unimplemented!(),
}
pt = point;
}
Progress { status: Err(_), point } => {
return shunting_yard.finish(point);
}
}
}
}
}
} |
Reported as rust-lang/rust#41888. |
Closing because the upstream issue has been fixed. |
Consider the following program:
I expect it to exit normally with no output; the parser fails, but we discard the error. And indeed this is exactly the behavior I observe when I run the program in debug mode. However, when I run it in release mode with
panic=abort
, with this Cargo.toml:then the program exits with a segmentation fault.
The text was updated successfully, but these errors were encountered: