@@ -13,7 +13,7 @@ use rustc_ast::util::classify;
1313use rustc_ast:: util:: literal:: LitError ;
1414use rustc_ast:: util:: parser:: { prec_let_scrutinee_needs_par, AssocOp , Fixity } ;
1515use rustc_ast_pretty:: pprust;
16- use rustc_errors:: { Applicability , PResult } ;
16+ use rustc_errors:: { Applicability , DiagnosticBuilder , PResult } ;
1717use rustc_span:: source_map:: { self , Span , Spanned } ;
1818use rustc_span:: symbol:: { kw, sym, Symbol } ;
1919use std:: mem;
@@ -1068,8 +1068,8 @@ impl<'a> Parser<'a> {
10681068 }
10691069
10701070 fn parse_path_start_expr ( & mut self , attrs : AttrVec ) -> PResult < ' a , P < Expr > > {
1071- let lo = self . token . span ;
10721071 let path = self . parse_path ( PathStyle :: Expr ) ?;
1072+ let lo = path. span ;
10731073
10741074 // `!`, as an operator, is prefix, so we know this isn't that.
10751075 let ( hi, kind) = if self . eat ( & token:: Not ) {
@@ -1081,7 +1081,7 @@ impl<'a> Parser<'a> {
10811081 } ;
10821082 ( self . prev_token . span , ExprKind :: MacCall ( mac) )
10831083 } else if self . check ( & token:: OpenDelim ( token:: Brace ) ) {
1084- if let Some ( expr) = self . maybe_parse_struct_expr ( lo , & path, & attrs) {
1084+ if let Some ( expr) = self . maybe_parse_struct_expr ( & path, & attrs) {
10851085 return expr;
10861086 } else {
10871087 ( path. span , ExprKind :: Path ( None , path) )
@@ -1895,16 +1895,15 @@ impl<'a> Parser<'a> {
18951895
18961896 fn maybe_parse_struct_expr (
18971897 & mut self ,
1898- lo : Span ,
18991898 path : & ast:: Path ,
19001899 attrs : & AttrVec ,
19011900 ) -> Option < PResult < ' a , P < Expr > > > {
19021901 let struct_allowed = !self . restrictions . contains ( Restrictions :: NO_STRUCT_LITERAL ) ;
19031902 if struct_allowed || self . is_certainly_not_a_block ( ) {
19041903 // This is a struct literal, but we don't can't accept them here.
1905- let expr = self . parse_struct_expr ( lo , path. clone ( ) , attrs. clone ( ) ) ;
1904+ let expr = self . parse_struct_expr ( path. clone ( ) , attrs. clone ( ) ) ;
19061905 if let ( Ok ( expr) , false ) = ( & expr, struct_allowed) {
1907- self . error_struct_lit_not_allowed_here ( lo , expr. span ) ;
1906+ self . error_struct_lit_not_allowed_here ( path . span , expr. span ) ;
19081907 }
19091908 return Some ( expr) ;
19101909 }
@@ -1923,17 +1922,23 @@ impl<'a> Parser<'a> {
19231922
19241923 pub ( super ) fn parse_struct_expr (
19251924 & mut self ,
1926- lo : Span ,
19271925 pth : ast:: Path ,
19281926 mut attrs : AttrVec ,
19291927 ) -> PResult < ' a , P < Expr > > {
1930- let struct_sp = lo. to ( self . prev_token . span ) ;
19311928 self . bump ( ) ;
19321929 let mut fields = Vec :: new ( ) ;
19331930 let mut base = None ;
1931+ let mut recover_async = false ;
19341932
19351933 attrs. extend ( self . parse_inner_attributes ( ) ?) ;
19361934
1935+ let mut async_block_err = |e : & mut DiagnosticBuilder < ' _ > , span : Span | {
1936+ recover_async = true ;
1937+ e. span_label ( span, "`async` blocks are only allowed in the 2018 edition" ) ;
1938+ e. help ( "set `edition = \" 2018\" ` in `Cargo.toml`" ) ;
1939+ e. note ( "for more on editions, read https://doc.rust-lang.org/edition-guide" ) ;
1940+ } ;
1941+
19371942 while self . token != token:: CloseDelim ( token:: Brace ) {
19381943 if self . eat ( & token:: DotDot ) {
19391944 let exp_span = self . prev_token . span ;
@@ -1952,7 +1957,11 @@ impl<'a> Parser<'a> {
19521957 let parsed_field = match self . parse_field ( ) {
19531958 Ok ( f) => Some ( f) ,
19541959 Err ( mut e) => {
1955- e. span_label ( struct_sp, "while parsing this struct" ) ;
1960+ if pth == kw:: Async {
1961+ async_block_err ( & mut e, pth. span ) ;
1962+ } else {
1963+ e. span_label ( pth. span , "while parsing this struct" ) ;
1964+ }
19561965 e. emit ( ) ;
19571966
19581967 // If the next token is a comma, then try to parse
@@ -1976,15 +1985,19 @@ impl<'a> Parser<'a> {
19761985 }
19771986 }
19781987 Err ( mut e) => {
1979- e. span_label ( struct_sp, "while parsing this struct" ) ;
1980- if let Some ( f) = recovery_field {
1981- fields. push ( f) ;
1982- e. span_suggestion (
1983- self . prev_token . span . shrink_to_hi ( ) ,
1984- "try adding a comma" ,
1985- "," . into ( ) ,
1986- Applicability :: MachineApplicable ,
1987- ) ;
1988+ if pth == kw:: Async {
1989+ async_block_err ( & mut e, pth. span ) ;
1990+ } else {
1991+ e. span_label ( pth. span , "while parsing this struct" ) ;
1992+ if let Some ( f) = recovery_field {
1993+ fields. push ( f) ;
1994+ e. span_suggestion (
1995+ self . prev_token . span . shrink_to_hi ( ) ,
1996+ "try adding a comma" ,
1997+ "," . into ( ) ,
1998+ Applicability :: MachineApplicable ,
1999+ ) ;
2000+ }
19882001 }
19892002 e. emit ( ) ;
19902003 self . recover_stmt_ ( SemiColonMode :: Comma , BlockMode :: Ignore ) ;
@@ -1993,9 +2006,10 @@ impl<'a> Parser<'a> {
19932006 }
19942007 }
19952008
1996- let span = lo . to ( self . token . span ) ;
2009+ let span = pth . span . to ( self . token . span ) ;
19972010 self . expect ( & token:: CloseDelim ( token:: Brace ) ) ?;
1998- Ok ( self . mk_expr ( span, ExprKind :: Struct ( pth, fields, base) , attrs) )
2011+ let expr = if recover_async { ExprKind :: Err } else { ExprKind :: Struct ( pth, fields, base) } ;
2012+ Ok ( self . mk_expr ( span, expr, attrs) )
19992013 }
20002014
20012015 /// Use in case of error after field-looking code: `S { foo: () with a }`.
0 commit comments