22
33use rustc_ast:: { self as ast, Attribute , Lit , LitKind , MetaItem , MetaItemKind , NestedMetaItem } ;
44use rustc_ast_pretty:: pprust;
5- use rustc_errors:: { struct_span_err, Applicability } ;
5+ use rustc_errors:: { struct_span_err, Applicability , Handler } ;
66use rustc_feature:: { find_gated_cfg, is_builtin_attr_name, Features , GatedCfg } ;
77use rustc_macros:: HashStable_Generic ;
88use rustc_session:: parse:: { feature_err, ParseSess } ;
@@ -827,6 +827,150 @@ pub enum ReprAttr {
827827 ReprNoNiche ,
828828}
829829
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+
830974#[ derive( Eq , PartialEq , Debug , Copy , Clone ) ]
831975#[ derive( Encodable , Decodable , HashStable_Generic ) ]
832976pub enum IntType {
@@ -846,98 +990,32 @@ impl IntType {
846990 }
847991}
848992
849- /// Parse #[repr(...)] forms.
993+ /// Parse ` #[repr(...)]` forms.
850994///
851995/// Valid repr contents: any of the primitive integral type names (see
852996/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
853997/// the same discriminant size that the corresponding C enum would or C
854998/// structure layout, `packed` to remove padding, and `transparent` to elegate representation
855999/// concerns to the only non-ZST field.
8561000pub fn find_repr_attrs ( sess : & Session , attr : & Attribute ) -> Vec < ReprAttr > {
857- use ReprAttr :: * ;
858-
8591001 let mut acc = Vec :: new ( ) ;
8601002 let diagnostic = & sess. parse_sess . span_diagnostic ;
8611003 if attr. has_name ( sym:: repr) {
8621004 if let Some ( items) = attr. meta_item_list ( ) {
8631005 sess. mark_attr_used ( attr) ;
8641006 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))
8791014 }
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" )
8941018 }
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" ) ;
9411019 }
9421020 }
9431021 }
0 commit comments