@@ -21,6 +21,7 @@ use crate::errors::{
21
21
22
22
use crate :: fluent_generated as fluent;
23
23
use crate :: parser;
24
+ use crate :: parser:: attr:: InnerAttrPolicy ;
24
25
use rustc_ast as ast;
25
26
use rustc_ast:: ptr:: P ;
26
27
use rustc_ast:: token:: { self , Delimiter , Lit , LitKind , TokenKind } ;
@@ -722,6 +723,101 @@ impl<'a> Parser<'a> {
722
723
Err ( err)
723
724
}
724
725
726
+ pub ( super ) fn attr_on_non_tail_expr ( & self , expr : & Expr ) {
727
+ // Missing semicolon typo error.
728
+ let span = self . prev_token . span . shrink_to_hi ( ) ;
729
+ let mut err = self . sess . create_err ( ExpectedSemi {
730
+ span,
731
+ token : self . token . clone ( ) ,
732
+ unexpected_token_label : Some ( self . token . span ) ,
733
+ sugg : ExpectedSemiSugg :: AddSemi ( span) ,
734
+ } ) ;
735
+ let attr_span = match & expr. attrs [ ..] {
736
+ [ ] => unreachable ! ( ) ,
737
+ [ only] => only. span ,
738
+ [ first, rest @ ..] => {
739
+ for attr in rest {
740
+ err. span_label ( attr. span , "" ) ;
741
+ }
742
+ first. span
743
+ }
744
+ } ;
745
+ err. span_label (
746
+ attr_span,
747
+ format ! (
748
+ "only `;` terminated statements or tail expressions are allowed after {}" ,
749
+ if expr. attrs. len( ) == 1 { "this attribute" } else { "these attributes" } ,
750
+ ) ,
751
+ ) ;
752
+ if self . token == token:: Pound
753
+ && self . look_ahead ( 1 , |t| t. kind == token:: OpenDelim ( Delimiter :: Bracket ) )
754
+ {
755
+ // We have
756
+ // #[attr]
757
+ // expr
758
+ // #[not_attr]
759
+ // other_expr
760
+ err. span_label ( span, "expected `;` here" ) ;
761
+ err. multipart_suggestion (
762
+ "alternatively, consider surrounding the expression with a block" ,
763
+ vec ! [
764
+ ( expr. span. shrink_to_lo( ) , "{ " . to_string( ) ) ,
765
+ ( expr. span. shrink_to_hi( ) , " }" . to_string( ) ) ,
766
+ ] ,
767
+ Applicability :: MachineApplicable ,
768
+ ) ;
769
+ let mut snapshot = self . create_snapshot_for_diagnostic ( ) ;
770
+ if let [ attr] = & expr. attrs [ ..]
771
+ && let ast:: AttrKind :: Normal ( attr_kind) = & attr. kind
772
+ && let [ segment] = & attr_kind. item . path . segments [ ..]
773
+ && segment. ident . name == sym:: cfg
774
+ && let Ok ( next_attr) = snapshot. parse_attribute ( InnerAttrPolicy :: Forbidden ( None ) )
775
+ && let ast:: AttrKind :: Normal ( next_attr_kind) = next_attr. kind
776
+ && let [ next_segment] = & next_attr_kind. item . path . segments [ ..]
777
+ && segment. ident . name == sym:: cfg
778
+ && let Ok ( next_expr) = snapshot. parse_expr ( )
779
+ {
780
+ // We have for sure
781
+ // #[cfg(..)]
782
+ // expr
783
+ // #[cfg(..)]
784
+ // other_expr
785
+ // So we suggest using `if cfg!(..) { expr } else if cfg!(..) { other_expr }`.
786
+ let margin = self . sess . source_map ( ) . span_to_margin ( next_expr. span ) . unwrap_or ( 0 ) ;
787
+ let sugg = vec ! [
788
+ ( attr. span. with_hi( segment. span( ) . hi( ) ) , "if cfg!" . to_string( ) ) ,
789
+ (
790
+ attr_kind. item. args. span( ) . unwrap( ) . shrink_to_hi( ) . with_hi( attr. span. hi( ) ) ,
791
+ " {" . to_string( ) ,
792
+ ) ,
793
+ ( expr. span. shrink_to_lo( ) , " " . to_string( ) ) ,
794
+ (
795
+ next_attr. span. with_hi( next_segment. span( ) . hi( ) ) ,
796
+ "} else if cfg!" . to_string( ) ,
797
+ ) ,
798
+ (
799
+ next_attr_kind
800
+ . item
801
+ . args
802
+ . span( )
803
+ . unwrap( )
804
+ . shrink_to_hi( )
805
+ . with_hi( next_attr. span. hi( ) ) ,
806
+ " {" . to_string( ) ,
807
+ ) ,
808
+ ( next_expr. span. shrink_to_lo( ) , " " . to_string( ) ) ,
809
+ ( next_expr. span. shrink_to_hi( ) , format!( "\n {}}}" , " " . repeat( margin) ) ) ,
810
+ ] ;
811
+ err. multipart_suggestion (
812
+ "it seems like you are trying to provide different expressions depending on \
813
+ `cfg`, consider using `if cfg!(..)`",
814
+ sugg,
815
+ Applicability :: MachineApplicable ,
816
+ ) ;
817
+ }
818
+ }
819
+ err. emit ( ) ;
820
+ }
725
821
fn check_too_many_raw_str_terminators ( & mut self , err : & mut Diagnostic ) -> bool {
726
822
let sm = self . sess . source_map ( ) ;
727
823
match ( & self . prev_token . kind , & self . token . kind ) {
0 commit comments