@@ -60,6 +60,7 @@ use std::u16;
60
60
use std:: u32;
61
61
use std:: u64;
62
62
use std:: u8;
63
+ use std:: cell:: RefCell ;
63
64
use collections:: SmallIntMap ;
64
65
use syntax:: abi;
65
66
use syntax:: ast_map;
@@ -482,6 +483,9 @@ struct Context<'a> {
482
483
/// Level of lints for certain NodeIds, stored here because the body of
483
484
/// the lint needs to run in trans.
484
485
node_levels : HashMap < ( ast:: NodeId , Lint ) , ( Level , LintSource ) > ,
486
+
487
+ /// ids of structs which have had a representation note emitted with ctypes
488
+ checked_ffi_structs : RefCell < NodeSet > ,
485
489
}
486
490
487
491
pub fn emit_lint ( level : Level , src : LintSource , msg : & str , span : Span ,
@@ -923,26 +927,55 @@ fn check_type_limits(cx: &Context, e: &ast::Expr) {
923
927
}
924
928
925
929
fn check_item_ctypes ( cx : & Context , it : & ast:: Item ) {
926
- fn check_ty ( cx : & Context , ty : & ast:: Ty ) {
927
- match ty . node {
930
+ fn check_ty ( cx : & Context , aty : & ast:: Ty ) {
931
+ match aty . node {
928
932
ast:: TyPath ( _, _, id) => {
929
933
match cx. tcx . def_map . borrow ( ) . get_copy ( & id) {
930
934
ast:: DefPrimTy ( ast:: TyInt ( ast:: TyI ) ) => {
931
- cx. span_lint ( CTypes , ty . span ,
935
+ cx. span_lint ( CTypes , aty . span ,
932
936
"found rust type `int` in foreign module, while \
933
937
libc::c_int or libc::c_long should be used") ;
934
938
}
935
939
ast:: DefPrimTy ( ast:: TyUint ( ast:: TyU ) ) => {
936
- cx. span_lint ( CTypes , ty . span ,
940
+ cx. span_lint ( CTypes , aty . span ,
937
941
"found rust type `uint` in foreign module, while \
938
942
libc::c_uint or libc::c_ulong should be used") ;
939
943
}
940
944
ast:: DefTy ( def_id) => {
941
- if !adt:: is_ffi_safe ( cx. tcx , def_id) {
942
- cx. span_lint ( CTypes , ty. span ,
943
- "found enum type without foreign-function-safe \
944
- representation annotation in foreign module") ;
945
- // hmm... this message could be more helpful
945
+ match adt:: is_ffi_safe ( cx. tcx , def_id) {
946
+ Ok ( _) => { } ,
947
+ Err ( types) => {
948
+ // in the enum case, we don't care about
949
+ // "fields".
950
+
951
+ let ty = ty:: get ( ty:: lookup_item_type ( cx. tcx , def_id) . ty ) ;
952
+
953
+ match ty. sty {
954
+ ty:: ty_struct( _, _) => {
955
+ cx. span_lint ( CTypes , aty. span , "found struct without \
956
+ FFI-safe representation used in FFI") ;
957
+
958
+ for def_id in types. iter ( ) {
959
+ if !cx. checked_ffi_structs . borrow_mut ( )
960
+ . insert ( def_id. node ) {
961
+ return ;
962
+ }
963
+
964
+ match cx. tcx . map . opt_span ( def_id. node ) {
965
+ Some ( sp) => cx. tcx . sess . span_note ( sp, "consider \
966
+ adding `#[repr(C)]` to this type") ,
967
+ None => { }
968
+ }
969
+ }
970
+ } ,
971
+ ty:: ty_enum( _, _) => {
972
+ cx. span_lint ( CTypes , aty. span ,
973
+ "found enum without FFI-safe representation \
974
+ annotation used in FFI") ;
975
+ }
976
+ _ => { }
977
+ }
978
+ }
946
979
}
947
980
}
948
981
_ => ( )
@@ -1100,6 +1133,7 @@ static obsolete_attrs: &'static [(&'static str, &'static str)] = &[
1100
1133
( "fast_ffi" , "Remove it" ) ,
1101
1134
( "fixed_stack_segment" , "Remove it" ) ,
1102
1135
( "rust_stack" , "Remove it" ) ,
1136
+ ( "packed" , "Use `#[repr(packed)]` instead" )
1103
1137
] ;
1104
1138
1105
1139
static other_attrs: & ' static [ & ' static str ] = & [
@@ -1109,7 +1143,7 @@ static other_attrs: &'static [&'static str] = &[
1109
1143
"allow" , "deny" , "forbid" , "warn" , // lint options
1110
1144
"deprecated" , "experimental" , "unstable" , "stable" , "locked" , "frozen" , //item stability
1111
1145
"cfg" , "doc" , "export_name" , "link_section" ,
1112
- "no_mangle" , "static_assert" , "unsafe_no_drop_flag" , "packed" ,
1146
+ "no_mangle" , "static_assert" , "unsafe_no_drop_flag" ,
1113
1147
"simd" , "repr" , "deriving" , "unsafe_destructor" , "link" , "phase" ,
1114
1148
"macro_export" , "must_use" , "automatically_derived" ,
1115
1149
@@ -1178,6 +1212,10 @@ fn check_unused_attribute(cx: &Context, attrs: &[ast::Attribute]) {
1178
1212
// FIXME: #14408 whitelist docs since rustdoc looks at them
1179
1213
"doc" ,
1180
1214
1215
+ // Just because a struct isn't used for FFI in *this* crate, doesn't
1216
+ // mean it won't ever be.
1217
+ "repr" ,
1218
+
1181
1219
// FIXME: #14406 these are processed in trans, which happens after the
1182
1220
// lint pass
1183
1221
"address_insignificant" ,
@@ -1189,7 +1227,6 @@ fn check_unused_attribute(cx: &Context, attrs: &[ast::Attribute]) {
1189
1227
"no_builtins" ,
1190
1228
"no_mangle" ,
1191
1229
"no_split_stack" ,
1192
- "packed" ,
1193
1230
"static_assert" ,
1194
1231
"thread_local" ,
1195
1232
@@ -1977,6 +2014,7 @@ pub fn check_crate(tcx: &ty::ctxt,
1977
2014
negated_expr_id : -1 ,
1978
2015
checked_raw_pointers : NodeSet :: new ( ) ,
1979
2016
node_levels : HashMap :: new ( ) ,
2017
+ checked_ffi_structs : RefCell :: new ( NodeSet :: new ( ) ) ,
1980
2018
} ;
1981
2019
1982
2020
// Install default lint levels, followed by the command line levels, and
0 commit comments