2
2
3
3
use rustc_ast:: { self as ast, Attribute , Lit , LitKind , MetaItem , MetaItemKind , NestedMetaItem } ;
4
4
use rustc_ast_pretty:: pprust;
5
- use rustc_errors:: { struct_span_err, Applicability } ;
5
+ use rustc_errors:: { struct_span_err, Applicability , Handler } ;
6
6
use rustc_feature:: { find_gated_cfg, is_builtin_attr_name, Features , GatedCfg } ;
7
7
use rustc_macros:: HashStable_Generic ;
8
8
use rustc_session:: parse:: { feature_err, ParseSess } ;
@@ -827,6 +827,150 @@ pub enum ReprAttr {
827
827
ReprNoNiche ,
828
828
}
829
829
830
+ impl ReprAttr {
831
+ fn try_from_meta_item (
832
+ diagnostic : & Handler ,
833
+ item : & MetaItem ,
834
+ ) -> Result < /* incorrect attr if None */ Option < Self > , /* invalid attr */ ( ) > {
835
+ use ReprAttr :: * ;
836
+ let name = item. name_or_empty ( ) ;
837
+ let expect_no_args = || {
838
+ if !item. is_word ( ) {
839
+ struct_span_err ! (
840
+ diagnostic,
841
+ item. span,
842
+ E0589 ,
843
+ "invalid `repr({})` attribute: no arguments expected" ,
844
+ name,
845
+ )
846
+ . span_suggestion (
847
+ item. path . span . shrink_to_hi ( ) . to ( item. span . shrink_to_hi ( ) ) ,
848
+ "remove additional values" ,
849
+ format ! ( "{}" , name) ,
850
+ Applicability :: MachineApplicable ,
851
+ )
852
+ . emit ( ) ;
853
+ }
854
+ } ;
855
+ let expect_one_int_arg = || {
856
+ if let MetaItemKind :: NameValue ( ref value) = item. kind {
857
+ let mut err = struct_span_err ! (
858
+ diagnostic,
859
+ item. span,
860
+ E0693 ,
861
+ "incorrect `repr({})` attribute format" ,
862
+ name
863
+ ) ;
864
+ match value. kind {
865
+ ast:: LitKind :: Int ( int, ast:: LitIntType :: Unsuffixed ) => {
866
+ err. span_suggestion (
867
+ item. span ,
868
+ "use parentheses instead" ,
869
+ format ! ( "{}({})" , name, int) ,
870
+ Applicability :: MachineApplicable ,
871
+ ) ;
872
+ }
873
+ ast:: LitKind :: Str ( s, _) => {
874
+ err. span_suggestion (
875
+ item. span ,
876
+ "use parentheses instead" ,
877
+ format ! ( "{}({})" , name, s) ,
878
+ Applicability :: MachineApplicable ,
879
+ ) ;
880
+ }
881
+ _ => { }
882
+ }
883
+ err. emit ( ) ;
884
+ } else if item. is_word ( ) || matches ! ( item. meta_item_list( ) , Some ( [ ] ) ) {
885
+ struct_span_err ! (
886
+ diagnostic,
887
+ item. span,
888
+ E0693 ,
889
+ "invalid `repr({})` attribute: expected a value" ,
890
+ name
891
+ )
892
+ . span_suggestion (
893
+ item. span ,
894
+ "add a value" ,
895
+ format ! ( "{}(/* value */)" , name) ,
896
+ Applicability :: HasPlaceholders ,
897
+ )
898
+ . emit ( ) ;
899
+ } else if let Some ( [ NestedMetaItem :: Literal ( value) ] ) = item. meta_item_list ( ) {
900
+ match parse_alignment ( & value. kind ) {
901
+ Ok ( literal) => return Some ( literal) ,
902
+ Err ( message) => {
903
+ struct_span_err ! (
904
+ diagnostic,
905
+ item. span,
906
+ E0589 ,
907
+ "invalid `repr({})` attribute: {}" ,
908
+ name,
909
+ message
910
+ )
911
+ . emit ( ) ;
912
+ }
913
+ } ;
914
+ } else if let Some ( [ first_meta, .., last_meta] ) = item. meta_item_list ( ) {
915
+ struct_span_err ! (
916
+ diagnostic,
917
+ item. span,
918
+ E0693 ,
919
+ "invalid `repr({})` attribute: expected only one value" ,
920
+ item. name_or_empty( ) ,
921
+ )
922
+ . span_label ( first_meta. span ( ) . to ( last_meta. span ( ) ) , "only one argument expected" )
923
+ . emit ( ) ;
924
+ }
925
+ return None ;
926
+ } ;
927
+ // Every possible repr variant must be covered here or else an ICE will occur
928
+ Ok ( Some ( match name {
929
+ sym:: C => {
930
+ expect_no_args ( ) ;
931
+ ReprC
932
+ }
933
+ sym:: simd => {
934
+ expect_no_args ( ) ;
935
+ ReprSimd
936
+ }
937
+ sym:: transparent => {
938
+ expect_no_args ( ) ;
939
+ ReprTransparent
940
+ }
941
+ sym:: no_niche => {
942
+ expect_no_args ( ) ;
943
+ ReprNoNiche
944
+ }
945
+ sym:: align => {
946
+ if let Some ( arg) = expect_one_int_arg ( ) {
947
+ ReprAlign ( arg)
948
+ } else {
949
+ return Ok ( None ) ;
950
+ }
951
+ }
952
+ sym:: packed => {
953
+ if item. is_word ( ) {
954
+ ReprPacked ( 1 )
955
+ } else if let Some ( arg) = expect_one_int_arg ( ) {
956
+ ReprPacked ( arg)
957
+ } else {
958
+ return Ok ( None ) ;
959
+ }
960
+ }
961
+ name => {
962
+ if let Some ( ty) = int_type_of_word ( name) {
963
+ expect_no_args ( ) ;
964
+ ReprInt ( ty)
965
+ } else {
966
+ // Unrecognized repr attr
967
+ return Err ( ( ) ) ;
968
+ }
969
+ }
970
+ } ) )
971
+ }
972
+ }
973
+
830
974
#[ derive( Eq , PartialEq , Debug , Copy , Clone ) ]
831
975
#[ derive( Encodable , Decodable , HashStable_Generic ) ]
832
976
pub enum IntType {
@@ -846,98 +990,32 @@ impl IntType {
846
990
}
847
991
}
848
992
849
- /// Parse #[repr(...)] forms.
993
+ /// Parse ` #[repr(...)]` forms.
850
994
///
851
995
/// Valid repr contents: any of the primitive integral type names (see
852
996
/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
853
997
/// the same discriminant size that the corresponding C enum would or C
854
998
/// structure layout, `packed` to remove padding, and `transparent` to elegate representation
855
999
/// concerns to the only non-ZST field.
856
1000
pub fn find_repr_attrs ( sess : & Session , attr : & Attribute ) -> Vec < ReprAttr > {
857
- use ReprAttr :: * ;
858
-
859
1001
let mut acc = Vec :: new ( ) ;
860
1002
let diagnostic = & sess. parse_sess . span_diagnostic ;
861
1003
if attr. has_name ( sym:: repr) {
862
1004
if let Some ( items) = attr. meta_item_list ( ) {
863
1005
sess. mark_attr_used ( attr) ;
864
1006
for item in items {
865
- let mut recognised = false ;
866
- if item. is_word ( ) {
867
- let hint = match item. name_or_empty ( ) {
868
- sym:: C => Some ( ReprC ) ,
869
- sym:: packed => Some ( ReprPacked ( 1 ) ) ,
870
- sym:: simd => Some ( ReprSimd ) ,
871
- sym:: transparent => Some ( ReprTransparent ) ,
872
- sym:: no_niche => Some ( ReprNoNiche ) ,
873
- name => int_type_of_word ( name) . map ( ReprInt ) ,
874
- } ;
875
-
876
- if let Some ( h) = hint {
877
- recognised = true ;
878
- acc. push ( h) ;
1007
+ match item
1008
+ . meta_item ( )
1009
+ . ok_or ( ( ) )
1010
+ . and_then ( |item| ReprAttr :: try_from_meta_item ( diagnostic, & item) )
1011
+ {
1012
+ Ok ( None ) => {
1013
+ // Recognized attribute, but failed to parse (e.g. align() or packed(1, 2, 3))
879
1014
}
880
- } else if let Some ( ( name, value) ) = item. name_value_literal ( ) {
881
- let mut literal_error = None ;
882
- if name == sym:: align {
883
- recognised = true ;
884
- match parse_alignment ( & value. kind ) {
885
- Ok ( literal) => acc. push ( ReprAlign ( literal) ) ,
886
- Err ( message) => literal_error = Some ( message) ,
887
- } ;
888
- } else if name == sym:: packed {
889
- recognised = true ;
890
- match parse_alignment ( & value. kind ) {
891
- Ok ( literal) => acc. push ( ReprPacked ( literal) ) ,
892
- Err ( message) => literal_error = Some ( message) ,
893
- } ;
1015
+ Ok ( Some ( attr) ) => acc. push ( attr) ,
1016
+ Err ( ( ) ) => {
1017
+ diagnostic. delay_span_bug ( item. span ( ) , "unrecognized representation hint" )
894
1018
}
895
- if let Some ( literal_error) = literal_error {
896
- struct_span_err ! (
897
- diagnostic,
898
- item. span( ) ,
899
- E0589 ,
900
- "invalid `repr(align)` attribute: {}" ,
901
- literal_error
902
- )
903
- . emit ( ) ;
904
- }
905
- } else if let Some ( meta_item) = item. meta_item ( ) {
906
- if meta_item. has_name ( sym:: align) {
907
- if let MetaItemKind :: NameValue ( ref value) = meta_item. kind {
908
- recognised = true ;
909
- let mut err = struct_span_err ! (
910
- diagnostic,
911
- item. span( ) ,
912
- E0693 ,
913
- "incorrect `repr(align)` attribute format"
914
- ) ;
915
- match value. kind {
916
- ast:: LitKind :: Int ( int, ast:: LitIntType :: Unsuffixed ) => {
917
- err. span_suggestion (
918
- item. span ( ) ,
919
- "use parentheses instead" ,
920
- format ! ( "align({})" , int) ,
921
- Applicability :: MachineApplicable ,
922
- ) ;
923
- }
924
- ast:: LitKind :: Str ( s, _) => {
925
- err. span_suggestion (
926
- item. span ( ) ,
927
- "use parentheses instead" ,
928
- format ! ( "align({})" , s) ,
929
- Applicability :: MachineApplicable ,
930
- ) ;
931
- }
932
- _ => { }
933
- }
934
- err. emit ( ) ;
935
- }
936
- }
937
- }
938
- if !recognised {
939
- // Not a word we recognize
940
- diagnostic. delay_span_bug ( item. span ( ) , "unrecognized representation hint" ) ;
941
1019
}
942
1020
}
943
1021
}
0 commit comments