@@ -80,6 +80,37 @@ declare_lint! {
8080 "proper use of libc types in foreign item definitions"
8181}
8282
83+ declare_lint ! {
84+ /// The `improper_c_var_definitions` lint detects incorrect use of
85+ /// [`no_mangle`] and [`export_name`] static variable definitions.
86+ /// (In other words, static variables accessible by name by foreign code.)
87+ ///
88+ /// [`no_mangle`]: https://doc.rust-lang.org/stable/reference/abi.html#the-no_mangle-attribute
89+ /// [`export_name`]: https://doc.rust-lang.org/stable/reference/abi.html#the-export_name-attribute
90+ ///
91+ /// ### Example
92+ ///
93+ /// ```rust
94+ /// # #[unsafe(no_mangle)]
95+ /// # #[used]
96+ /// static mut PLUGIN_ABI_MIN_VERSION: &'static str = "0.0.5";
97+ /// ```
98+ ///
99+ /// {{produces}}
100+ ///
101+ /// ### Explanation
102+ ///
103+ /// The compiler has several checks to verify that types used in
104+ /// static variables exposed to foreign code are safe and follow
105+ /// certain rules to ensure proper compatibility with the foreign interfaces.
106+ /// This lint is issued when it detects a probable mistake in a definition.
107+ /// The lint usually should provide a description of the issue,
108+ /// along with possibly a hint on how to resolve it.
109+ pub ( crate ) IMPROPER_C_VAR_DEFINITIONS ,
110+ Warn ,
111+ "proper use of libc types in foreign-reachable static variable definitions"
112+ }
113+
83114declare_lint ! {
84115 /// The `improper_c_callbacks` lint detects incorrect use of
85116 /// [`extern` function] pointers.
@@ -166,6 +197,7 @@ declare_lint! {
166197declare_lint_pass ! ( ImproperCTypesLint => [
167198 IMPROPER_CTYPES ,
168199 IMPROPER_C_FN_DEFINITIONS ,
200+ IMPROPER_C_VAR_DEFINITIONS ,
169201 IMPROPER_C_CALLBACKS ,
170202 USES_POWER_ALIGNMENT ,
171203] ) ;
@@ -247,6 +279,8 @@ enum CItemKind {
247279 ImportedExtern ,
248280 /// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
249281 ExportedFunction ,
282+ /// `no_mangle`/`export_name` static variables, assumed to be used from across an FFI boundary,
283+ ExportedStatic ,
250284 /// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
251285 Callback ,
252286}
@@ -595,6 +629,8 @@ impl VisitorState {
595629 // Unfortunately, "cannot call non-const operator in constants" (bitwise or?).
596630 const NONE : Self = Self :: empty ( ) ;
597631 const STATIC_TY : Self = Self :: STATIC ;
632+ const EXPORTED_STATIC_TY : Self =
633+ Self :: from_bits ( Self :: STATIC . bits ( ) | Self :: DEFINED . bits ( ) ) . unwrap ( ) ;
598634 const ARGUMENT_TY_IN_DEFINITION : Self =
599635 Self :: from_bits ( Self :: FUNC . bits ( ) | Self :: DEFINED . bits ( ) ) . unwrap ( ) ;
600636 const RETURN_TY_IN_DEFINITION : Self =
@@ -1645,6 +1681,14 @@ impl<'tcx> ImproperCTypesLint {
16451681 self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
16461682 }
16471683
1684+ /// Check that a `#[no_mangle]`/`#[export_name = _]` static variable is of a ffi-safe type.
1685+ fn check_exported_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1686+ let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1687+ let visitor = ImproperCTypesVisitor :: new ( cx) ;
1688+ let ffi_res = visitor. check_type ( VisitorState :: EXPORTED_STATIC_TY , ty) ;
1689+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ExportedStatic ) ;
1690+ }
1691+
16481692 /// Check if a function's argument types and result type are "ffi-safe".
16491693 fn check_foreign_fn (
16501694 & mut self ,
@@ -1745,11 +1789,13 @@ impl<'tcx> ImproperCTypesLint {
17451789 let lint = match fn_mode {
17461790 CItemKind :: ImportedExtern => IMPROPER_CTYPES ,
17471791 CItemKind :: ExportedFunction => IMPROPER_C_FN_DEFINITIONS ,
1792+ CItemKind :: ExportedStatic => IMPROPER_C_VAR_DEFINITIONS ,
17481793 CItemKind :: Callback => IMPROPER_C_CALLBACKS ,
17491794 } ;
17501795 let desc = match fn_mode {
17511796 CItemKind :: ImportedExtern => "`extern` block" ,
17521797 CItemKind :: ExportedFunction => "`extern` fn" ,
1798+ CItemKind :: ExportedStatic => "foreign-code-reachable static" ,
17531799 CItemKind :: Callback => "`extern` callback" ,
17541800 } ;
17551801 for reason in reasons. iter_mut ( ) {
@@ -1817,6 +1863,25 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
18171863 ty,
18181864 cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
18191865 ) ;
1866+
1867+ // FIXME: cx.tcx.has_attr no worky
1868+ // if matches!(item.kind, hir::ItemKind::Static(..))
1869+ // && (cx.tcx.has_attr(item.owner_id, sym::no_mangle)
1870+ // || cx.tcx.has_attr(item.owner_id, sym::export_name))
1871+ if matches ! ( item. kind, hir:: ItemKind :: Static ( ..) ) {
1872+ let is_exported_static = cx. tcx . get_all_attrs ( item. owner_id ) . iter ( ) . any ( |x| {
1873+ matches ! (
1874+ x,
1875+ hir:: Attribute :: Parsed (
1876+ hir:: attrs:: AttributeKind :: NoMangle ( _)
1877+ | hir:: attrs:: AttributeKind :: ExportName { .. }
1878+ )
1879+ )
1880+ } ) ;
1881+ if is_exported_static {
1882+ self . check_exported_static ( cx, item. owner_id , ty. span ) ;
1883+ }
1884+ }
18201885 }
18211886 // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
18221887 hir:: ItemKind :: Fn { .. } => { }
0 commit comments