1+ use crate :: errors:: { WhereClauseBeforeTupleStructBody , WhereClauseBeforeTupleStructBodySugg } ;
2+
13use super :: { ForceCollect , Parser , TrailingToken } ;
24
5+ use ast:: token:: Delimiter ;
36use rustc_ast:: token;
47use rustc_ast:: {
58 self as ast, AttrVec , GenericBounds , GenericParam , GenericParamKind , TyKind , WhereClause ,
69} ;
710use rustc_errors:: { Applicability , PResult } ;
8- use rustc_span:: symbol:: kw;
11+ use rustc_span:: symbol:: { kw, Ident } ;
12+ use rustc_span:: Span ;
13+
14+ enum PredicateOrStructBody {
15+ Predicate ( ast:: WherePredicate ) ,
16+ StructBody ( Vec < ast:: FieldDef > ) ,
17+ }
918
1019impl < ' a > Parser < ' a > {
1120 /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
@@ -240,23 +249,39 @@ impl<'a> Parser<'a> {
240249 } )
241250 }
242251
243- /// Parses an optional where-clause and places it in `generics` .
252+ /// Parses an optional where-clause.
244253 ///
245254 /// ```ignore (only-for-syntax-highlight)
246255 /// where T : Trait<U, V> + 'b, 'a : 'b
247256 /// ```
248257 pub ( super ) fn parse_where_clause ( & mut self ) -> PResult < ' a , WhereClause > {
258+ self . parse_where_clause_common ( None ) . map ( |( clause, _) | clause)
259+ }
260+
261+ pub ( super ) fn parse_struct_where_clause (
262+ & mut self ,
263+ struct_name : Ident ,
264+ body_insertion_point : Span ,
265+ ) -> PResult < ' a , ( WhereClause , Option < Vec < ast:: FieldDef > > ) > {
266+ self . parse_where_clause_common ( Some ( ( struct_name, body_insertion_point) ) )
267+ }
268+
269+ fn parse_where_clause_common (
270+ & mut self ,
271+ struct_ : Option < ( Ident , Span ) > ,
272+ ) -> PResult < ' a , ( WhereClause , Option < Vec < ast:: FieldDef > > ) > {
249273 let mut where_clause = WhereClause {
250274 has_where_token : false ,
251275 predicates : Vec :: new ( ) ,
252276 span : self . prev_token . span . shrink_to_hi ( ) ,
253277 } ;
278+ let mut tuple_struct_body = None ;
254279
255280 if !self . eat_keyword ( kw:: Where ) {
256- return Ok ( where_clause) ;
281+ return Ok ( ( where_clause, None ) ) ;
257282 }
258283 where_clause. has_where_token = true ;
259- let lo = self . prev_token . span ;
284+ let where_lo = self . prev_token . span ;
260285
261286 // We are considering adding generics to the `where` keyword as an alternative higher-rank
262287 // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
@@ -272,21 +297,30 @@ impl<'a> Parser<'a> {
272297 }
273298
274299 loop {
275- let lo = self . token . span ;
300+ let where_sp = where_lo. to ( self . prev_token . span ) ;
301+ let pred_lo = self . token . span ;
276302 if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| !t. is_like_plus ( ) ) {
277303 let lifetime = self . expect_lifetime ( ) ;
278304 // Bounds starting with a colon are mandatory, but possibly empty.
279305 self . expect ( & token:: Colon ) ?;
280306 let bounds = self . parse_lt_param_bounds ( ) ;
281307 where_clause. predicates . push ( ast:: WherePredicate :: RegionPredicate (
282308 ast:: WhereRegionPredicate {
283- span : lo . to ( self . prev_token . span ) ,
309+ span : pred_lo . to ( self . prev_token . span ) ,
284310 lifetime,
285311 bounds,
286312 } ,
287313 ) ) ;
288314 } else if self . check_type ( ) {
289- where_clause. predicates . push ( self . parse_ty_where_predicate ( ) ?) ;
315+ match self . parse_ty_where_predicate_or_recover_tuple_struct_body (
316+ struct_, pred_lo, where_sp,
317+ ) ? {
318+ PredicateOrStructBody :: Predicate ( pred) => where_clause. predicates . push ( pred) ,
319+ PredicateOrStructBody :: StructBody ( body) => {
320+ tuple_struct_body = Some ( body) ;
321+ break ;
322+ }
323+ }
290324 } else {
291325 break ;
292326 }
@@ -297,7 +331,7 @@ impl<'a> Parser<'a> {
297331 if self . eat_keyword_noexpect ( kw:: Where ) {
298332 let msg = "cannot define duplicate `where` clauses on an item" ;
299333 let mut err = self . struct_span_err ( self . token . span , msg) ;
300- err. span_label ( lo , "previous `where` clause starts here" ) ;
334+ err. span_label ( pred_lo , "previous `where` clause starts here" ) ;
301335 err. span_suggestion_verbose (
302336 prev_token. shrink_to_hi ( ) . to ( self . prev_token . span ) ,
303337 "consider joining the two `where` clauses into one" ,
@@ -310,8 +344,72 @@ impl<'a> Parser<'a> {
310344 }
311345 }
312346
313- where_clause. span = lo. to ( self . prev_token . span ) ;
314- Ok ( where_clause)
347+ where_clause. span = where_lo. to ( self . prev_token . span ) ;
348+ Ok ( ( where_clause, tuple_struct_body) )
349+ }
350+
351+ fn parse_ty_where_predicate_or_recover_tuple_struct_body (
352+ & mut self ,
353+ struct_ : Option < ( Ident , Span ) > ,
354+ pred_lo : Span ,
355+ where_sp : Span ,
356+ ) -> PResult < ' a , PredicateOrStructBody > {
357+ let mut snapshot = None ;
358+
359+ if let Some ( struct_) = struct_
360+ && self . may_recover ( )
361+ && self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis )
362+ {
363+ snapshot = Some ( ( struct_, self . create_snapshot_for_diagnostic ( ) ) ) ;
364+ } ;
365+
366+ match self . parse_ty_where_predicate ( ) {
367+ Ok ( pred) => Ok ( PredicateOrStructBody :: Predicate ( pred) ) ,
368+ Err ( type_err) => {
369+ let Some ( ( ( struct_name, body_insertion_point) , mut snapshot) ) = snapshot else {
370+ return Err ( type_err) ;
371+ } ;
372+
373+ // Check if we might have encountered an out of place tuple struct body.
374+ match snapshot. parse_tuple_struct_body ( ) {
375+ // Since we don't know the exact reason why we failed to parse the
376+ // predicate (we might have stumbled upon something bogus like `(T): ?`),
377+ // employ a simple heuristic to weed out some pathological cases:
378+ // Look for a semicolon (strong indicator) or anything that might mark
379+ // the end of the item (weak indicator) following the body.
380+ Ok ( body)
381+ if matches ! ( snapshot. token. kind, token:: Semi | token:: Eof )
382+ || snapshot. token . can_begin_item ( ) =>
383+ {
384+ type_err. cancel ( ) ;
385+
386+ let body_sp = pred_lo. to ( snapshot. prev_token . span ) ;
387+ let map = self . sess . source_map ( ) ;
388+
389+ self . sess . emit_err ( WhereClauseBeforeTupleStructBody {
390+ span : where_sp,
391+ name : struct_name. span ,
392+ body : body_sp,
393+ sugg : map. span_to_snippet ( body_sp) . ok ( ) . map ( |body| {
394+ WhereClauseBeforeTupleStructBodySugg {
395+ left : body_insertion_point. shrink_to_hi ( ) ,
396+ snippet : body,
397+ right : map. end_point ( where_sp) . to ( body_sp) ,
398+ }
399+ } ) ,
400+ } ) ;
401+
402+ self . restore_snapshot ( snapshot) ;
403+ Ok ( PredicateOrStructBody :: StructBody ( body) )
404+ }
405+ Ok ( _) => Err ( type_err) ,
406+ Err ( body_err) => {
407+ body_err. cancel ( ) ;
408+ Err ( type_err)
409+ }
410+ }
411+ }
412+ }
315413 }
316414
317415 fn parse_ty_where_predicate ( & mut self ) -> PResult < ' a , ast:: WherePredicate > {
0 commit comments