@@ -23,8 +23,10 @@ mod improper_ctypes;
2323use crate :: lints:: {
2424 AmbiguousWidePointerComparisons , AmbiguousWidePointerComparisonsAddrMetadataSuggestion ,
2525 AmbiguousWidePointerComparisonsAddrSuggestion , AtomicOrderingFence , AtomicOrderingLoad ,
26- AtomicOrderingStore , ImproperCTypes , InvalidAtomicOrderingDiag , InvalidNanComparisons ,
27- InvalidNanComparisonsSuggestion , UnusedComparisons , VariantSizeDifferencesDiag ,
26+ AtomicOrderingStore , ImproperCTypes , InteriorMutableConstsDiag ,
27+ InteriorMutableConstsSuggestionAllow , InteriorMutableConstsSuggestionStatic ,
28+ InvalidAtomicOrderingDiag , InvalidNanComparisons , InvalidNanComparisonsSuggestion ,
29+ UnusedComparisons , VariantSizeDifferencesDiag ,
2830} ;
2931use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
3032
@@ -167,6 +169,37 @@ declare_lint! {
167169 "detects ambiguous wide pointer comparisons"
168170}
169171
172+ declare_lint ! {
173+ /// The `interior_mutable_consts` lint detects instance where
174+ /// const-items have a interior mutable type, which silently does nothing.
175+ ///
176+ /// ### Example
177+ ///
178+ /// ```
179+ /// use std::sync::Once;
180+ ///
181+ /// const A: Once = Once::new(); // using `B` will always duplicate `B` and never
182+ /// // modify it-self as it's a const-item and not a
183+ /// // static-item
184+ /// ```
185+ ///
186+ /// {{produces}}
187+ ///
188+ /// ### Explanation
189+ ///
190+ /// Using a const-item with an interior mutable type has no effect as const-item
191+ /// are essentially inlined wherever they are used, meaning that they are copied
192+ /// directly into the relevant context when used rendering modification through
193+ /// interior mutability ineffective across usage of that const-item.
194+ ///
195+ /// The current implementation of this lint only warns on significant `std` and
196+ /// `core` interior mutable types, like `Once`, `AtomicI32`, ... this is done out
197+ /// of prudence and may be extended in the future.
198+ INTERIOR_MUTABLE_CONSTS ,
199+ Warn ,
200+ "detects const items with interior mutable type" ,
201+ }
202+
170203#[ derive( Copy , Clone ) ]
171204pub ( crate ) struct TypeLimits {
172205 /// Id of the last visited negated expression
@@ -179,7 +212,8 @@ impl_lint_pass!(TypeLimits => [
179212 UNUSED_COMPARISONS ,
180213 OVERFLOWING_LITERALS ,
181214 INVALID_NAN_COMPARISONS ,
182- AMBIGUOUS_WIDE_POINTER_COMPARISONS
215+ AMBIGUOUS_WIDE_POINTER_COMPARISONS ,
216+ INTERIOR_MUTABLE_CONSTS ,
183217] ) ;
184218
185219impl TypeLimits {
@@ -513,6 +547,44 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
513547 } )
514548 }
515549 }
550+
551+ fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: Item < ' tcx > ) {
552+ if let hir:: ItemKind :: Const ( ty, _generics, _body_id) = item. kind
553+ && let hir:: TyKind :: Path ( ref qpath) = ty. kind
554+ && let Some ( def_id) = cx. qpath_res ( qpath, ty. hir_id ) . opt_def_id ( )
555+ && cx. tcx . has_attr ( def_id, sym:: rustc_significant_interior_mutable_type)
556+ && let Some ( ty_name) = cx. tcx . opt_item_ident ( def_id)
557+ {
558+ let ( sugg_static, sugg_allow) = if let Some ( vis_span) =
559+ item. vis_span . find_ancestor_inside ( item. span )
560+ && item. span . can_be_used_for_suggestions ( )
561+ && vis_span. can_be_used_for_suggestions ( )
562+ {
563+ (
564+ InteriorMutableConstsSuggestionStatic :: Spanful {
565+ const_ : item. vis_span . between ( item. ident . span ) ,
566+ before : if !vis_span. is_empty ( ) { " " } else { "" } ,
567+ } ,
568+ InteriorMutableConstsSuggestionAllow :: Spanful {
569+ span : item. span . shrink_to_lo ( ) ,
570+ } ,
571+ )
572+ } else {
573+ (
574+ InteriorMutableConstsSuggestionStatic :: Spanless ,
575+ InteriorMutableConstsSuggestionAllow :: Spanless ,
576+ )
577+ } ;
578+
579+ cx. emit_span_lint ( INTERIOR_MUTABLE_CONSTS , item. span , InteriorMutableConstsDiag {
580+ ty_name,
581+ ty_span : ty. span ,
582+ const_name : item. ident ,
583+ sugg_static,
584+ sugg_allow,
585+ } ) ;
586+ }
587+ }
516588}
517589
518590declare_lint ! {
0 commit comments