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