@@ -8,7 +8,7 @@ use rustc_macros::HashStable_Generic;
8
8
use rustc_session:: parse:: { feature_err, ParseSess } ;
9
9
use rustc_session:: Session ;
10
10
use rustc_span:: hygiene:: Transparency ;
11
- use rustc_span:: { symbol:: sym, symbol:: Symbol , Span } ;
11
+ use rustc_span:: { symbol:: sym, symbol:: Symbol , BytePos , Span } ;
12
12
use std:: num:: NonZeroU32 ;
13
13
14
14
pub fn is_builtin_attr ( attr : & Attribute ) -> bool {
@@ -843,10 +843,10 @@ impl ReprAttr {
843
843
"invalid `repr({})` attribute: no arguments expected" ,
844
844
name,
845
845
)
846
- . span_suggestion (
846
+ . span_suggestion_verbose (
847
847
item. path . span . shrink_to_hi ( ) . to ( item. span . shrink_to_hi ( ) ) ,
848
848
"remove additional values" ,
849
- format ! ( "{}" , name ) ,
849
+ String :: new ( ) ,
850
850
Applicability :: MachineApplicable ,
851
851
)
852
852
. emit ( ) ;
@@ -862,55 +862,107 @@ impl ReprAttr {
862
862
name
863
863
) ;
864
864
match value. kind {
865
- ast:: LitKind :: Int ( int, ast:: LitIntType :: Unsuffixed ) => {
866
- err. span_suggestion (
867
- item. span ,
865
+ ast:: LitKind :: Int ( _int, ast:: LitIntType :: Unsuffixed ) => {
866
+ let open_paren_span =
867
+ item. path . span . shrink_to_hi ( ) . to ( value. span . shrink_to_lo ( ) ) ;
868
+ let close_paren_span =
869
+ item. span . shrink_to_hi ( ) . to ( value. span . shrink_to_hi ( ) ) ;
870
+
871
+ err. multipart_suggestion (
868
872
"use parentheses instead" ,
869
- format ! ( "{}({})" , name, int) ,
873
+ vec ! [
874
+ ( open_paren_span, "(" . to_string( ) ) ,
875
+ ( close_paren_span, ")" . to_string( ) ) ,
876
+ ] ,
870
877
Applicability :: MachineApplicable ,
871
878
) ;
872
879
}
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
+ ast:: LitKind :: Str ( str, style) => {
881
+ // repr(foo = "123" )
882
+ // ^^^ ^
883
+ let open_paren_span =
884
+ item. path . span . shrink_to_hi ( ) . to ( value. span . shrink_to_lo ( ) ) ;
885
+ let close_paren_span =
886
+ item. span . shrink_to_hi ( ) . to ( value. span . shrink_to_hi ( ) ) ;
887
+ // repr(foo = "123" )
888
+ // ^^^^ ^^
889
+ // BytePos math is safe because strings can only be surrounded by single
890
+ // byte characters (`r`, `#`, and `"` are all one byte)
891
+ let open_paren_span = open_paren_span
892
+ . with_hi ( open_paren_span. hi ( ) + BytePos ( style. prefix_len ( ) ) ) ;
893
+ let close_paren_span = close_paren_span
894
+ . with_hi ( close_paren_span. lo ( ) - BytePos ( style. suffix_len ( ) ) ) ;
895
+
896
+ if str. is_empty ( ) {
897
+ // When encountering repr(foo = "") suggest additional help
898
+ err. span_suggestion_verbose (
899
+ open_paren_span. to ( close_paren_span) ,
900
+ "use parentheses instead and add a value" ,
901
+ "(/* value */)" . to_string ( ) ,
902
+ Applicability :: HasPlaceholders ,
903
+ ) ;
904
+ } else {
905
+ err. multipart_suggestion (
906
+ "use parentheses instead" ,
907
+ vec ! [
908
+ ( open_paren_span, "(" . to_string( ) ) ,
909
+ ( close_paren_span, ")" . to_string( ) ) ,
910
+ ] ,
911
+ Applicability :: MachineApplicable ,
912
+ ) ;
913
+
914
+ match str. as_str ( ) . parse :: < u128 > ( ) {
915
+ Ok ( num) => match is_alignment_valid ( num) {
916
+ Ok ( align) => {
917
+ err. emit ( ) ;
918
+ return Some ( align) ;
919
+ }
920
+ Err ( msg) => {
921
+ err. span_label ( value. span , msg) ;
922
+ }
923
+ } ,
924
+ Err ( _) => {
925
+ err. span_label ( value. span , "must be a non-negative number" ) ;
926
+ }
927
+ }
928
+ }
929
+ }
930
+ _ => {
931
+ err. span_label ( value. span , "must be a non-negative number" ) ;
880
932
}
881
- _ => { }
882
933
}
883
934
err. emit ( ) ;
884
935
} else if item. is_word ( ) || matches ! ( item. meta_item_list( ) , Some ( [ ] ) ) {
885
936
struct_span_err ! (
886
937
diagnostic,
887
938
item. span,
888
939
E0693 ,
889
- "invalid `repr({})` attribute: expected a value " ,
940
+ "invalid `repr({})` attribute: expected a non-negative number " ,
890
941
name
891
942
)
892
- . span_suggestion (
893
- item. span ,
943
+ . span_suggestion_verbose (
944
+ item. path . span . shrink_to_hi ( ) . to ( item . span . shrink_to_hi ( ) ) ,
894
945
"add a value" ,
895
- format ! ( "{} (/* value */)", name ) ,
946
+ " (/* value */)". to_string ( ) ,
896
947
Applicability :: HasPlaceholders ,
897
948
)
898
949
. 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 ( ) ;
950
+ } else if let Some ( [ meta] ) = item. meta_item_list ( ) {
951
+ match parse_alignment (
952
+ struct_span_err ! (
953
+ diagnostic,
954
+ meta. span( ) ,
955
+ E0589 ,
956
+ "invalid `repr({})` attribute" ,
957
+ name,
958
+ ) ,
959
+ meta,
960
+ ) {
961
+ Ok ( lit) => return Some ( lit) ,
962
+ Err ( ( ) ) => {
963
+ // parse_alignment already emitted an error
912
964
}
913
- } ;
965
+ }
914
966
} else if let Some ( [ first_meta, .., last_meta] ) = item. meta_item_list ( ) {
915
967
struct_span_err ! (
916
968
diagnostic,
@@ -1124,15 +1176,65 @@ fn allow_unstable<'a>(
1124
1176
} )
1125
1177
}
1126
1178
1127
- pub fn parse_alignment ( node : & ast:: LitKind ) -> Result < u32 , & ' static str > {
1128
- if let ast:: LitKind :: Int ( literal, ast:: LitIntType :: Unsuffixed ) = node {
1129
- if literal. is_power_of_two ( ) {
1130
- // rustc_middle::ty::layout::Align restricts align to <= 2^29
1131
- if * literal <= 1 << 29 { Ok ( * literal as u32 ) } else { Err ( "larger than 2^29" ) }
1179
+ pub fn parse_alignment (
1180
+ mut err : rustc_errors:: DiagnosticBuilder < ' _ > ,
1181
+ node : & ast:: NestedMetaItem ,
1182
+ ) -> Result < u32 , ( ) > {
1183
+ if let ast:: NestedMetaItem :: Literal ( lit) = node {
1184
+ if let ast:: LitKind :: Int ( val, ast:: LitIntType :: Unsuffixed ) = lit. kind {
1185
+ match is_alignment_valid ( val) {
1186
+ Ok ( align) => {
1187
+ err. cancel ( ) ;
1188
+ return Ok ( align) ;
1189
+ }
1190
+ Err ( msg) => {
1191
+ err. span_label ( lit. span , msg) ;
1192
+ }
1193
+ }
1194
+ } else if let ast:: LitKind :: Str ( sym, style) = lit. kind {
1195
+ match sym. as_str ( ) . parse :: < u128 > ( ) {
1196
+ Ok ( num) => match is_alignment_valid ( num) {
1197
+ Ok ( align) => {
1198
+ err. multipart_suggestion (
1199
+ "remove the quotes" ,
1200
+ vec ! [
1201
+ (
1202
+ lit. span. with_hi( lit. span. lo( ) + BytePos ( style. prefix_len( ) ) ) ,
1203
+ "" . to_string( ) ,
1204
+ ) ,
1205
+ (
1206
+ lit. span. with_lo( lit. span. hi( ) - BytePos ( style. suffix_len( ) ) ) ,
1207
+ "" . to_string( ) ,
1208
+ ) ,
1209
+ ] ,
1210
+ Applicability :: MachineApplicable ,
1211
+ ) ;
1212
+ err. emit ( ) ;
1213
+ return Ok ( align) ;
1214
+ }
1215
+ Err ( msg) => {
1216
+ err. span_label ( lit. span , msg) ;
1217
+ }
1218
+ } ,
1219
+ Err ( _) => {
1220
+ err. span_label ( lit. span , "must be a non-negative number" ) ;
1221
+ }
1222
+ }
1132
1223
} else {
1133
- Err ( "not a power of two" )
1224
+ err . span_label ( lit . span , "not an unsuffixed integer" ) ;
1134
1225
}
1135
1226
} else {
1136
- Err ( "not an unsuffixed integer" )
1227
+ err. span_label ( node. span ( ) , "not a non-negative number" ) ;
1228
+ }
1229
+ err. emit ( ) ;
1230
+ Err ( ( ) )
1231
+ }
1232
+
1233
+ fn is_alignment_valid ( n : u128 ) -> Result < u32 , & ' static str > {
1234
+ if n. is_power_of_two ( ) {
1235
+ // rustc_target::abi::Align restricts align to <= 2^29
1236
+ if n <= 1 << 29 { Ok ( n as u32 ) } else { Err ( "larger than 2^29" ) }
1237
+ } else {
1238
+ Err ( "not a power of two" )
1137
1239
}
1138
1240
}
0 commit comments