@@ -23,10 +23,11 @@ mod improper_ctypes;
23
23
use crate :: lints:: {
24
24
AmbiguousWidePointerComparisons , AmbiguousWidePointerComparisonsAddrMetadataSuggestion ,
25
25
AmbiguousWidePointerComparisonsAddrSuggestion , AtomicOrderingFence , AtomicOrderingLoad ,
26
- AtomicOrderingStore , ImproperCTypes , InvalidAtomicOrderingDiag , InvalidNanComparisons ,
27
- InvalidNanComparisonsSuggestion , UnpredictableFunctionPointerComparisons ,
28
- UnpredictableFunctionPointerComparisonsSuggestion , UnusedComparisons , UsesPowerAlignment ,
29
- VariantSizeDifferencesDiag ,
26
+ AtomicOrderingStore , ImproperCTypes , InteriorMutableConstsDiag ,
27
+ InteriorMutableConstsSuggestionAllow , InteriorMutableConstsSuggestionStatic ,
28
+ InvalidAtomicOrderingDiag , InvalidNanComparisons , InvalidNanComparisonsSuggestion ,
29
+ UnpredictableFunctionPointerComparisons , UnpredictableFunctionPointerComparisonsSuggestion ,
30
+ UnusedComparisons , UsesPowerAlignment , VariantSizeDifferencesDiag ,
30
31
} ;
31
32
use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
32
33
@@ -198,6 +199,47 @@ declare_lint! {
198
199
"detects unpredictable function pointer comparisons"
199
200
}
200
201
202
+ declare_lint ! {
203
+ /// The `interior_mutable_consts` lint detects instance where
204
+ /// const-items have a interior mutable type, which silently does nothing.
205
+ ///
206
+ /// ### Example
207
+ ///
208
+ /// ```rust
209
+ /// use std::sync::Once;
210
+ ///
211
+ /// // SAFETY: should only be call once
212
+ /// unsafe extern "C" fn ffi_init() { /* ... */ }
213
+ ///
214
+ /// const A: Once = Once::new(); // using `B` will always creates temporaries and
215
+ /// // never modify it-self on use, should be a
216
+ /// // static-item instead
217
+ ///
218
+ /// fn init() {
219
+ /// A.call_once(|| unsafe {
220
+ /// ffi_init(); // unsound, as the `call_once` is on a temporary
221
+ /// // and not on a shared variable
222
+ /// })
223
+ /// }
224
+ /// ```
225
+ ///
226
+ /// {{produces}}
227
+ ///
228
+ /// ### Explanation
229
+ ///
230
+ /// Using a const-item with an interior mutable type has no effect as const-item
231
+ /// are essentially inlined wherever they are used, meaning that they are copied
232
+ /// directly into the relevant context when used rendering modification through
233
+ /// interior mutability ineffective across usage of that const-item.
234
+ ///
235
+ /// The current implementation of this lint only warns on significant `std` and
236
+ /// `core` interior mutable types, like `Once`, `AtomicI32`, ... this is done out
237
+ /// of prudence and may be extended in the future.
238
+ INTERIOR_MUTABLE_CONSTS ,
239
+ Warn ,
240
+ "detects const items with interior mutable type" ,
241
+ }
242
+
201
243
#[ derive( Copy , Clone , Default ) ]
202
244
pub ( crate ) struct TypeLimits {
203
245
/// Id of the last visited negated expression
@@ -211,7 +253,8 @@ impl_lint_pass!(TypeLimits => [
211
253
OVERFLOWING_LITERALS ,
212
254
INVALID_NAN_COMPARISONS ,
213
255
AMBIGUOUS_WIDE_POINTER_COMPARISONS ,
214
- UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS
256
+ UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS ,
257
+ INTERIOR_MUTABLE_CONSTS ,
215
258
] ) ;
216
259
217
260
impl TypeLimits {
@@ -687,6 +730,48 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
687
730
} )
688
731
}
689
732
}
733
+
734
+ fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: Item < ' tcx > ) {
735
+ if let hir:: ItemKind :: Const ( ty, _generics, _body_id) = item. kind
736
+ && let hir:: TyKind :: Path ( ref qpath) = ty. kind
737
+ && let Some ( def_id) = cx. qpath_res ( qpath, ty. hir_id ) . opt_def_id ( )
738
+ && cx. tcx . has_attr ( def_id, sym:: rustc_significant_interior_mutable_type)
739
+ && let Some ( ty_name) = cx. tcx . opt_item_ident ( def_id)
740
+ {
741
+ let ( sugg_static, sugg_allow) = if let Some ( vis_span) =
742
+ item. vis_span . find_ancestor_inside ( item. span )
743
+ && item. span . can_be_used_for_suggestions ( )
744
+ && vis_span. can_be_used_for_suggestions ( )
745
+ {
746
+ (
747
+ InteriorMutableConstsSuggestionStatic :: Spanful {
748
+ const_ : item. vis_span . between ( item. ident . span ) ,
749
+ before : if !vis_span. is_empty ( ) { " " } else { "" } ,
750
+ } ,
751
+ InteriorMutableConstsSuggestionAllow :: Spanful {
752
+ span : item. span . shrink_to_lo ( ) ,
753
+ } ,
754
+ )
755
+ } else {
756
+ (
757
+ InteriorMutableConstsSuggestionStatic :: Spanless ,
758
+ InteriorMutableConstsSuggestionAllow :: Spanless ,
759
+ )
760
+ } ;
761
+
762
+ cx. emit_span_lint (
763
+ INTERIOR_MUTABLE_CONSTS ,
764
+ item. span ,
765
+ InteriorMutableConstsDiag {
766
+ ty_name,
767
+ ty_span : ty. span ,
768
+ const_name : item. ident ,
769
+ sugg_static,
770
+ sugg_allow,
771
+ } ,
772
+ ) ;
773
+ }
774
+ }
690
775
}
691
776
692
777
declare_lint ! {
0 commit comments