diff options
| author | Nick Cameron <ncameron@mozilla.com> | 2015-05-12 12:48:14 +1200 |
|---|---|---|
| committer | Nick Cameron <ncameron@mozilla.com> | 2015-05-12 12:48:14 +1200 |
| commit | e0216fcc42d5f4961d07378a783c87814097015f (patch) | |
| tree | e5f503c129942a2b7c2815b1c8e4db85b5bbcf1b /src/libsyntax | |
| parent | aa5ca282b20391c6df51fdfa94e0de5672ccfac1 (diff) | |
| parent | 750f2c63f2737305d33288303cdecb7a470a7922 (diff) | |
| download | rust-e0216fcc42d5f4961d07378a783c87814097015f.tar.gz rust-e0216fcc42d5f4961d07378a783c87814097015f.zip | |
Merge branch 'master' into
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/codemap.rs | 43 | ||||
| -rw-r--r-- | src/libsyntax/diagnostic.rs | 22 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/generic/mod.rs | 65 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 16 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/util/parser_testing.rs | 6 |
11 files changed, 110 insertions, 65 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3b7bfb1043a..e00cb82649b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -595,7 +595,7 @@ pub enum Pat_ { /// An associated const named using the qualified path `<T>::CONST` or /// `<T as Trait>::CONST`. Associated consts from inherent impls can be - /// refered to as simply `T::CONST`, in which case they will end up as + /// referred to as simply `T::CONST`, in which case they will end up as /// PatEnum, and the resolver will have to sort that out. PatQPath(QSelf, Path), diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5e0cb647c8b..348bf6f51bb 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -543,7 +543,7 @@ impl CodeMap { } } - pub fn new_filemap(&self, filename: FileName, src: String) -> Rc<FileMap> { + pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc<FileMap> { let mut files = self.files.borrow_mut(); let start_pos = match files.last() { None => 0, @@ -551,13 +551,9 @@ impl CodeMap { }; // Remove utf-8 BOM if any. - // FIXME #12884: no efficient/safe way to remove from the start of a string - // and reuse the allocation. - let mut src = if src.starts_with("\u{feff}") { - String::from(&src[3..]) - } else { - String::from(&src[..]) - }; + if src.starts_with("\u{feff}") { + src.drain(..3); + } // Append '\n' in case it's not already there. // This is a workaround to prevent CodeMap.lookup_filemap_idx from @@ -667,9 +663,22 @@ impl CodeMap { self.lookup_char_pos(sp.lo).file.name.to_string() } - pub fn span_to_lines(&self, sp: Span) -> FileLines { + pub fn span_to_lines(&self, sp: Span) -> FileLinesResult { + if sp.lo > sp.hi { + return Err(SpanLinesError::IllFormedSpan(sp)); + } + let lo = self.lookup_char_pos(sp.lo); let hi = self.lookup_char_pos(sp.hi); + + if lo.file.start_pos != hi.file.start_pos { + return Err(SpanLinesError::DistinctSources(DistinctSources { + begin: (lo.file.name.clone(), lo.file.start_pos), + end: (hi.file.name.clone(), hi.file.start_pos), + })); + } + assert!(hi.line >= lo.line); + let mut lines = Vec::with_capacity(hi.line - lo.line + 1); // The span starts partway through the first line, @@ -693,7 +702,7 @@ impl CodeMap { start_col: start_col, end_col: hi.col }); - FileLines {file: lo.file, lines: lines} + Ok(FileLines {file: lo.file, lines: lines}) } pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> { @@ -918,9 +927,17 @@ impl CodeMap { } // _____________________________________________________________________________ -// SpanSnippetError, DistinctSources, MalformedCodemapPositions +// SpanLinesError, SpanSnippetError, DistinctSources, MalformedCodemapPositions // +pub type FileLinesResult = Result<FileLines, SpanLinesError>; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SpanLinesError { + IllFormedSpan(Span), + DistinctSources(DistinctSources), +} + #[derive(Clone, PartialEq, Eq, Debug)] pub enum SpanSnippetError { IllFormedSpan(Span), @@ -1086,7 +1103,7 @@ mod tests { // Test span_to_lines for a span ending at the end of filemap let cm = init_code_map(); let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; - let file_lines = cm.span_to_lines(span); + let file_lines = cm.span_to_lines(span).unwrap(); assert_eq!(file_lines.file.name, "blork.rs"); assert_eq!(file_lines.lines.len(), 1); @@ -1131,7 +1148,7 @@ mod tests { assert_eq!(&cm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD"); // check that span_to_lines gives us the complete result with the lines/cols we expected - let lines = cm.span_to_lines(span); + let lines = cm.span_to_lines(span).unwrap(); let expected = vec![ LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) }, LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) }, diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index a7453636c44..aa649b4d99a 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -522,7 +522,7 @@ fn highlight_suggestion(err: &mut EmitterWriter, suggestion: &str) -> io::Result<()> { - let lines = cm.span_to_lines(sp); + let lines = cm.span_to_lines(sp).unwrap(); assert!(!lines.lines.is_empty()); // To build up the result, we want to take the snippet from the first @@ -567,9 +567,17 @@ fn highlight_lines(err: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span, lvl: Level, - lines: codemap::FileLines) + lines: codemap::FileLinesResult) -> io::Result<()> { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut err.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + let fm = &*lines.file; let line_strings: Option<Vec<&str>> = @@ -690,8 +698,16 @@ fn end_highlight_lines(w: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span, lvl: Level, - lines: codemap::FileLines) + lines: codemap::FileLinesResult) -> io::Result<()> { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut w.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + let fm = &*lines.file; let lines = &lines.lines[..]; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index cde16d25412..354a0bff749 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -146,7 +146,7 @@ pub trait AstBuilder { fn expr_lit(&self, sp: Span, lit: ast::Lit_) -> P<ast::Expr>; fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr>; - fn expr_int(&self, sp: Span, i: isize) -> P<ast::Expr>; + fn expr_isize(&self, sp: Span, i: isize) -> P<ast::Expr>; fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr>; fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr>; fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr>; @@ -698,7 +698,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr> { self.expr_lit(span, ast::LitInt(i as u64, ast::UnsignedIntLit(ast::TyUs))) } - fn expr_int(&self, sp: Span, i: isize) -> P<ast::Expr> { + fn expr_isize(&self, sp: Span, i: isize) -> P<ast::Expr> { self.expr_lit(sp, ast::LitInt(i as u64, ast::SignedIntLit(ast::TyIs, ast::Sign::new(i)))) } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 4a54b36f8c4..78c2faea9d2 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -77,7 +77,7 @@ //! //! The `cs_...` functions ("combine substructure) are designed to //! make life easier by providing some pre-made recipes for common -//! tasks; mostly calling the function being derived on all the +//! threads; mostly calling the function being derived on all the //! arguments and then combining them back together in some way (or //! letting the user chose that). They are not meant to be the only //! way to handle the structures that this code creates. @@ -270,7 +270,7 @@ pub struct Substructure<'a> { } /// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo { +pub struct FieldInfo<'a> { pub span: Span, /// None for tuple structs/normal enum variants, Some for normal /// structs/struct enum variants. @@ -281,6 +281,8 @@ pub struct FieldInfo { /// The expressions corresponding to references to this field in /// the other `Self` arguments. pub other: Vec<P<Expr>>, + /// The attributes on the field + pub attrs: &'a [ast::Attribute], } /// Fields for a static method @@ -293,11 +295,11 @@ pub enum StaticFields { /// A summary of the possible sets of fields. pub enum SubstructureFields<'a> { - Struct(Vec<FieldInfo>), + Struct(Vec<FieldInfo<'a>>), /// Matching variants of the enum: variant index, ast::Variant, /// fields: the field name is only non-`None` in the case of a struct /// variant. - EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>), + EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo<'a>>), /// Non-matching variants of the enum, but with all state hidden from /// the consequent code. The first component holds `Ident`s for all of @@ -617,7 +619,7 @@ impl<'a> TraitDef<'a> { fn expand_struct_def(&self, cx: &mut ExtCtxt, - struct_def: &StructDef, + struct_def: &'a StructDef, type_ident: Ident, generics: &Generics) -> P<ast::Item> { let field_tys: Vec<P<ast::Ty>> = struct_def.fields.iter() @@ -661,7 +663,7 @@ impl<'a> TraitDef<'a> { fn expand_enum_def(&self, cx: &mut ExtCtxt, - enum_def: &EnumDef, + enum_def: &'a EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, generics: &Generics) -> P<ast::Item> { @@ -893,10 +895,10 @@ impl<'a> MethodDef<'a> { /// } /// } /// ``` - fn expand_struct_method_body(&self, + fn expand_struct_method_body<'b>(&self, cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &StructDef, + trait_: &TraitDef<'b>, + struct_def: &'b StructDef, type_ident: Ident, self_args: &[P<Expr>], nonself_args: &[P<Expr>]) @@ -922,18 +924,19 @@ impl<'a> MethodDef<'a> { let fields = if !raw_fields.is_empty() { let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); let first_field = raw_fields.next().unwrap(); - let mut other_fields: Vec<vec::IntoIter<(Span, Option<Ident>, P<Expr>)>> + let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect(); - first_field.map(|(span, opt_id, field)| { + first_field.map(|(span, opt_id, field, attrs)| { FieldInfo { span: span, name: opt_id, self_: field, other: other_fields.iter_mut().map(|l| { match l.next().unwrap() { - (_, _, ex) => ex + (_, _, ex, _) => ex } - }).collect() + }).collect(), + attrs: attrs, } }).collect() } else { @@ -1007,10 +1010,10 @@ impl<'a> MethodDef<'a> { /// `PartialEq`, and those subcomputations will hopefully be removed /// as their results are unused. The point of `__self_vi` and /// `__arg_1_vi` is for `PartialOrd`; see #15503.) - fn expand_enum_method_body(&self, + fn expand_enum_method_body<'b>(&self, cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, self_args: Vec<P<Expr>>, @@ -1046,11 +1049,11 @@ impl<'a> MethodDef<'a> { /// } /// } /// ``` - fn build_enum_match_tuple( + fn build_enum_match_tuple<'b>( &self, cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, self_args: Vec<P<Expr>>, @@ -1133,7 +1136,7 @@ impl<'a> MethodDef<'a> { // arg fields of the variant for the first self pat. let field_tuples = first_self_pat_idents.into_iter().enumerate() // For each arg field of self, pull out its getter expr ... - .map(|(field_index, (sp, opt_ident, self_getter_expr))| { + .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| { // ... but FieldInfo also wants getter expr // for matching other arguments of Self type; // so walk across the *other* self_pats_idents @@ -1141,7 +1144,7 @@ impl<'a> MethodDef<'a> { // of them (using `field_index` tracked above). // That is the heart of the transposition. let others = self_pats_idents.iter().map(|fields| { - let (_, _opt_ident, ref other_getter_expr) = + let (_, _opt_ident, ref other_getter_expr, _) = fields[field_index]; // All Self args have same variant, so @@ -1157,6 +1160,7 @@ impl<'a> MethodDef<'a> { name: opt_ident, self_: self_getter_expr, other: others, + attrs: attrs, } }).collect::<Vec<FieldInfo>>(); @@ -1408,10 +1412,12 @@ impl<'a> TraitDef<'a> { fn create_struct_pattern(&self, cx: &mut ExtCtxt, struct_path: ast::Path, - struct_def: &StructDef, + struct_def: &'a StructDef, prefix: &str, mutbl: ast::Mutability) - -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>) { + -> (P<ast::Pat>, Vec<(Span, Option<Ident>, + P<Expr>, + &'a [ast::Attribute])>) { if struct_def.fields.is_empty() { return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); } @@ -1441,7 +1447,7 @@ impl<'a> TraitDef<'a> { paths.push(codemap::Spanned{span: sp, node: ident}); let val = cx.expr( sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident))))); - ident_expr.push((sp, opt_id, val)); + ident_expr.push((sp, opt_id, val, &struct_field.node.attrs[..])); } let subpats = self.create_subpatterns(cx, paths, mutbl); @@ -1449,7 +1455,8 @@ impl<'a> TraitDef<'a> { // struct_type is definitely not Unknown, since struct_def.fields // must be nonempty to reach here let pattern = if struct_type == Record { - let field_pats = subpats.into_iter().zip(ident_expr.iter()).map(|(pat, &(_, id, _))| { + let field_pats = subpats.into_iter().zip(ident_expr.iter()) + .map(|(pat, &(_, id, _, _))| { // id is guaranteed to be Some codemap::Spanned { span: pat.span, @@ -1467,10 +1474,10 @@ impl<'a> TraitDef<'a> { fn create_enum_variant_pattern(&self, cx: &mut ExtCtxt, enum_ident: ast::Ident, - variant: &ast::Variant, + variant: &'a ast::Variant, prefix: &str, mutbl: ast::Mutability) - -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>) { + -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); match variant.node.kind { @@ -1480,7 +1487,7 @@ impl<'a> TraitDef<'a> { } let mut paths = Vec::new(); - let mut ident_expr = Vec::new(); + let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new(); for (i, va) in variant_args.iter().enumerate() { let sp = self.set_expn_info(cx, va.ty.span); let ident = cx.ident_of(&format!("{}_{}", prefix, i)); @@ -1488,7 +1495,7 @@ impl<'a> TraitDef<'a> { paths.push(path1); let expr_path = cx.expr_path(cx.path_ident(sp, ident)); let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path))); - ident_expr.push((sp, None, val)); + ident_expr.push((sp, None, val, &[])); } let subpats = self.create_subpatterns(cx, paths, mutbl); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b8a79b0658d..476ab0fbf11 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -934,9 +934,10 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> { let fm = fresh_mark(); let marked_before = mark_tts(&tts[..], fm); let mac_span = fld.cx.original_span(); - let expanded = match expander.expand(fld.cx, - mac_span, - &marked_before[..]).make_pat() { + let pat = expander.expand(fld.cx, + mac_span, + &marked_before[..]).make_pat(); + let expanded = match pat { Some(e) => e, None => { fld.cx.span_err( diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 275400009f5..330fe86deeb 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -27,6 +27,7 @@ #![feature(associated_consts)] #![feature(collections)] +#![feature(collections_drain)] #![feature(core)] #![feature(libc)] #![feature(rustc_private)] diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5f76c214927..eb1c338ac85 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -88,7 +88,6 @@ use std::slice; bitflags! { flags Restrictions: u8 { - const UNRESTRICTED = 0, const RESTRICTION_STMT_EXPR = 1 << 0, const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1, } @@ -339,7 +338,7 @@ impl<'a> Parser<'a> { buffer_start: 0, buffer_end: 0, tokens_consumed: 0, - restrictions: Restrictions::UNRESTRICTED, + restrictions: Restrictions::empty(), quote_depth: 0, obsolete_set: HashSet::new(), mod_path_stack: Vec::new(), @@ -2991,7 +2990,7 @@ impl<'a> Parser<'a> { /// Parse an expression pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> { - return self.parse_expr_res(Restrictions::UNRESTRICTED); + self.parse_expr_res(Restrictions::empty()) } /// Parse an expression, subject to the given restrictions @@ -4775,7 +4774,7 @@ impl<'a> Parser<'a> { return self.parse_single_struct_field(Inherited, attrs); } - /// Parse visibility: PUB, PRIV, or nothing + /// Parse visibility: PUB or nothing fn parse_visibility(&mut self) -> PResult<Visibility> { if try!(self.eat_keyword(keywords::Pub)) { Ok(Public) } else { Ok(Inherited) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0106de913bb..53ed4f351d3 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -601,7 +601,7 @@ pub type IdentInterner = StrInterner; // if an interner exists in TLS, return it. Otherwise, prepare a // fresh one. -// FIXME(eddyb) #8726 This should probably use a task-local reference. +// FIXME(eddyb) #8726 This should probably use a thread-local reference. pub fn get_ident_interner() -> Rc<IdentInterner> { thread_local!(static KEY: Rc<::parse::token::IdentInterner> = { Rc::new(mk_fresh_ident_interner()) @@ -615,14 +615,14 @@ pub fn reset_ident_interner() { interner.reset(mk_fresh_ident_interner()); } -/// Represents a string stored in the task-local interner. Because the -/// interner lives for the life of the task, this can be safely treated as an -/// immortal string, as long as it never crosses between tasks. +/// Represents a string stored in the thread-local interner. Because the +/// interner lives for the life of the thread, this can be safely treated as an +/// immortal string, as long as it never crosses between threads. /// /// FIXME(pcwalton): You must be careful about what you do in the destructors /// of objects stored in TLS, because they may run after the interner is /// destroyed. In particular, they must not access string contents. This can -/// be fixed in the future by just leaking all strings until task death +/// be fixed in the future by just leaking all strings until thread death /// somehow. #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] pub struct InternedString { @@ -697,14 +697,14 @@ impl Encodable for InternedString { } } -/// Returns the string contents of a name, using the task-local interner. +/// Returns the string contents of a name, using the thread-local interner. #[inline] pub fn get_name(name: ast::Name) -> InternedString { let interner = get_ident_interner(); InternedString::new_from_rc_str(interner.get(name)) } -/// Returns the string contents of an identifier, using the task-local +/// Returns the string contents of an identifier, using the thread-local /// interner. #[inline] pub fn get_ident(ident: ast::Ident) -> InternedString { @@ -712,7 +712,7 @@ pub fn get_ident(ident: ast::Ident) -> InternedString { } /// Interns and returns the string contents of an identifier, using the -/// task-local interner. +/// thread-local interner. #[inline] pub fn intern_and_get_ident(s: &str) -> InternedString { get_name(intern(s)) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 828a334a40f..5a002dd790f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -902,10 +902,10 @@ impl<'a> State<'a> { try!(self.print_generics(params)); try!(self.end()); // end the inner ibox + try!(self.print_where_clause(¶ms.where_clause)); try!(space(&mut self.s)); try!(self.word_space("=")); try!(self.print_type(&**ty)); - try!(self.print_where_clause(¶ms.where_clause)); try!(word(&mut self.s, ";")); try!(self.end()); // end the outer ibox } diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index d016eb39239..929f2a6abd6 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -73,7 +73,11 @@ pub fn string_to_stmt(source_str : String) -> P<ast::Stmt> { /// Parse a string, return a pat. Uses "irrefutable"... which doesn't /// (currently) affect parsing. pub fn string_to_pat(source_str: String) -> P<ast::Pat> { - string_to_parser(&new_parse_sess(), source_str).parse_pat() + // Binding `sess` and `parser` works around dropck-injected + // region-inference issues; see #25212, #22323, #22321. + let sess = new_parse_sess(); + let mut parser = string_to_parser(&sess, source_str); + parser.parse_pat() } /// Convert a vector of strings to a vector of ast::Ident's |
