From 88b7603b167dd7cbd03522e37ad9f7dec18cae23 Mon Sep 17 00:00:00 2001 From: kennytm Date: Wed, 6 Jun 2018 23:20:22 +0800 Subject: [PATCH] Lint against const items which are interior mutable. Fix #1560. --- clippy_lints/src/lib.rs | 6 + clippy_lints/src/non_copy_const.rs | 268 ++++++++++++++++++++++++++++ tests/ui/non_copy_const.rs | 147 +++++++++++++++ tests/ui/non_copy_const.stderr | 275 +++++++++++++++++++++++++++++ 4 files changed, 696 insertions(+) create mode 100644 clippy_lints/src/non_copy_const.rs create mode 100644 tests/ui/non_copy_const.rs create mode 100644 tests/ui/non_copy_const.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 621b21429..99692de03 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -175,6 +175,7 @@ pub mod neg_cmp_op_on_partial_ord; pub mod neg_multiply; pub mod new_without_default; pub mod no_effect; +pub mod non_copy_const; pub mod non_expressive_names; pub mod ok_if_let; pub mod open_options; @@ -432,6 +433,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box duration_subsec::DurationSubsec); reg.register_late_lint_pass(box default_trait_access::DefaultTraitAccess); reg.register_late_lint_pass(box indexing_slicing::IndexingSlicing); + reg.register_late_lint_pass(box non_copy_const::NonCopyConst); reg.register_lint_group("clippy_restriction", vec![ arithmetic::FLOAT_ARITHMETIC, @@ -640,6 +642,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { new_without_default::NEW_WITHOUT_DEFAULT_DERIVE, no_effect::NO_EFFECT, no_effect::UNNECESSARY_OPERATION, + non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, + non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, non_expressive_names::MANY_SINGLE_CHAR_NAMES, ok_if_let::IF_LET_SOME_RESULT, @@ -895,6 +899,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { misc::CMP_NAN, misc::FLOAT_CMP, misc::MODULO_ONE, + non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, + non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, open_options::NONSENSICAL_OPEN_OPTIONS, ptr::MUT_FROM_REF, ranges::ITERATOR_STEP_BY_ZERO, diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs new file mode 100644 index 000000000..5fcf54bc0 --- /dev/null +++ b/clippy_lints/src/non_copy_const.rs @@ -0,0 +1,268 @@ +//! Checks for uses of const which the type is not Freeze (Cell-free). +//! +//! This lint is **deny** by default. + +use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass}; +use rustc::hir::*; +use rustc::hir::def::Def; +use rustc::ty::{self, TyRef, TypeFlags}; +use rustc::ty::adjustment::Adjust; +use rustc_errors::Applicability; +use rustc_typeck::hir_ty_to_ty; +use syntax_pos::{DUMMY_SP, Span}; +use std::ptr; +use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then}; + +/// **What it does:** Checks for declaration of `const` items which is interior +/// mutable (e.g. contains a `Cell`, `Mutex`, `AtomicXxxx` etc). +/// +/// **Why is this bad?** Consts are copied everywhere they are referenced, i.e. +/// every time you refer to the const a fresh instance of the `Cell` or `Mutex` +/// or `AtomicXxxx` will be created, which defeats the whole purpose of using +/// these types in the first place. +/// +/// The `const` should better be replaced by a `static` item if a global +/// variable is wanted, or replaced by a `const fn` if a constructor is wanted. +/// +/// **Known problems:** A "non-constant" const item is a legacy way to supply an +/// initialized value to downstream `static` items (e.g. the +/// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, +/// and this lint should be suppressed. +/// +/// **Example:** +/// ```rust +/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize}; +/// +/// // Bad. +/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); +/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged +/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct +/// +/// // Good. +/// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15); +/// STATIC_ATOM.store(9, SeqCst); +/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance +/// ``` +declare_clippy_lint! { + pub DECLARE_INTERIOR_MUTABLE_CONST, + correctness, + "declaring const with interior mutability" +} + +/// **What it does:** Checks if `const` items which is interior mutable (e.g. +/// contains a `Cell`, `Mutex`, `AtomicXxxx` etc) has been borrowed directly. +/// +/// **Why is this bad?** Consts are copied everywhere they are referenced, i.e. +/// every time you refer to the const a fresh instance of the `Cell` or `Mutex` +/// or `AtomicXxxx` will be created, which defeats the whole purpose of using +/// these types in the first place. +/// +/// The `const` value should be stored inside a `static` item. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize}; +/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); +/// +/// // Bad. +/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged +/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct +/// +/// // Good. +/// static STATIC_ATOM: AtomicUsize = CONST_ATOM; +/// STATIC_ATOM.store(9, SeqCst); +/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance +/// ``` +declare_clippy_lint! { + pub BORROW_INTERIOR_MUTABLE_CONST, + correctness, + "referencing const with interior mutability" +} + +#[derive(Copy, Clone)] +enum Source { + Item { + item: Span, + }, + Assoc { + item: Span, + ty: Span, + }, + Expr { + expr: Span, + }, +} + +impl Source { + fn lint(&self) -> (&'static Lint, &'static str, Span) { + match self { + Source::Item { item } | Source::Assoc { item, .. } => ( + DECLARE_INTERIOR_MUTABLE_CONST, + "a const item should never be interior mutable", + *item, + ), + Source::Expr { expr } => ( + BORROW_INTERIOR_MUTABLE_CONST, + "a const item with interior mutability should not be borrowed", + *expr, + ), + } + } +} + +fn verify_ty_bound<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + ty: ty::Ty<'tcx>, + source: Source, +) { + if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) { + // an UnsafeCell is !Copy, and an UnsafeCell is also the only type which + // is !Freeze, thus if our type is Copy we can be sure it must be Freeze + // as well. + return; + } + + let (lint, msg, span) = source.lint(); + span_lint_and_then(cx, lint, span, msg, |db| { + if in_macro(span) { + return; // Don't give suggestions into macros. + } + match source { + Source::Item { .. } => { + let const_kw_span = span.from_inner_byte_pos(0, 5); + db.span_suggestion_with_applicability( + const_kw_span, + "make this a static item", + "static".to_string(), + Applicability::MachineApplicable, + ); + } + Source::Assoc { ty: ty_span, .. } => { + if ty.flags.contains(TypeFlags::HAS_FREE_LOCAL_NAMES) { + db.span_help(ty_span, &format!("consider requiring `{}` to be `Copy`", ty)); + } + } + Source::Expr { .. } => { + db.help( + "assign this const to a local or static variable, and use the variable here", + ); + } + } + }); +} + + +pub struct NonCopyConst; + +impl LintPass for NonCopyConst { + fn get_lints(&self) -> LintArray { + lint_array!(DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx Item) { + if let ItemConst(hir_ty, ..) = &it.node { + let ty = hir_ty_to_ty(cx.tcx, hir_ty); + verify_ty_bound(cx, ty, Source::Item { item: it.span }); + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx TraitItem) { + if let TraitItemKind::Const(hir_ty, ..) = &trait_item.node { + let ty = hir_ty_to_ty(cx.tcx, hir_ty); + verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: trait_item.span }); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx ImplItem) { + if let ImplItemKind::Const(hir_ty, ..) = &impl_item.node { + let item_node_id = cx.tcx.hir.get_parent_node(impl_item.id); + let item = cx.tcx.hir.expect_item(item_node_id); + // ensure the impl is an inherent impl. + if let ItemImpl(_, _, _, _, None, _, _) = item.node { + let ty = hir_ty_to_ty(cx.tcx, hir_ty); + verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: impl_item.span }); + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + if let ExprPath(qpath) = &expr.node { + // Only lint if we use the const item inside a function. + if in_constant(cx, expr.id) { + return; + } + + // make sure it is a const item. + match cx.tables.qpath_def(qpath, expr.hir_id) { + Def::Const(_) | Def::AssociatedConst(_) => {}, + _ => return, + }; + + // climb up to resolve any field access and explicit referencing. + let mut cur_expr = expr; + let mut dereferenced_expr = expr; + let mut needs_check_adjustment = true; + loop { + let parent_id = cx.tcx.hir.get_parent_node(cur_expr.id); + if parent_id == cur_expr.id { + break; + } + if let Some(map::NodeExpr(parent_expr)) = cx.tcx.hir.find(parent_id) { + match &parent_expr.node { + ExprAddrOf(..) => { + // `&e` => `e` must be referenced + needs_check_adjustment = false; + } + ExprField(..) => { + dereferenced_expr = parent_expr; + needs_check_adjustment = true; + } + ExprIndex(e, _) if ptr::eq(&**e, cur_expr) => { + // `e[i]` => desugared to `*Index::index(&e, i)`, + // meaning `e` must be referenced. + // no need to go further up since a method call is involved now. + needs_check_adjustment = false; + break; + } + ExprUnary(UnDeref, _) => { + // `*e` => desugared to `*Deref::deref(&e)`, + // meaning `e` must be referenced. + // no need to go further up since a method call is involved now. + needs_check_adjustment = false; + break; + } + _ => break, + } + cur_expr = parent_expr; + } else { + break; + } + } + + let ty = if !needs_check_adjustment { + cx.tables.expr_ty(dereferenced_expr) + } else { + let adjustments = cx.tables.expr_adjustments(dereferenced_expr); + if let Some(i) = adjustments.iter().position(|adj| match adj.kind { + Adjust::Borrow(_) | Adjust::Deref(_) => true, + _ => false, + }) { + if i == 0 { + cx.tables.expr_ty(dereferenced_expr) + } else { + adjustments[i - 1].target + } + } else { + // No borrow adjustments = the entire const is moved. + return; + } + }; + + verify_ty_bound(cx, ty, Source::Expr { expr: expr.span }); + } + } +} diff --git a/tests/ui/non_copy_const.rs b/tests/ui/non_copy_const.rs new file mode 100644 index 000000000..d7391577d --- /dev/null +++ b/tests/ui/non_copy_const.rs @@ -0,0 +1,147 @@ +#![feature(const_string_new, const_vec_new)] +#![allow(ref_in_deref, dead_code)] + +use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; +use std::cell::Cell; +use std::sync::Once; +use std::borrow::Cow; +use std::fmt::Display; + +const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable +const CELL: Cell = Cell::new(6); //~ ERROR interior mutable +const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); +//~^ ERROR interior mutable + +macro_rules! declare_const { + ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; +} +declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + +// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. + +const INTEGER: u8 = 8; +const STRING: String = String::new(); +const STR: &str = "012345"; +const COW: Cow = Cow::Borrowed("abcdef"); +//^ note: a const item of Cow is used in the `postgres` package. + +const NO_ANN: &Display = &70; + +static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); +//^ there should be no lints on this line + +#[allow(declare_interior_mutable_const)] +const ONCE_INIT: Once = Once::new(); + +trait Trait: Copy { + type NonCopyType; + + const ATOMIC: AtomicUsize; //~ ERROR interior mutable + const INTEGER: u64; + const STRING: String; + const SELF: Self; // (no error) + const INPUT: T; + //~^ ERROR interior mutable + //~| HELP consider requiring `T` to be `Copy` + const ASSOC: Self::NonCopyType; + //~^ ERROR interior mutable + //~| HELP consider requiring `>::NonCopyType` to be `Copy` + + const AN_INPUT: T = Self::INPUT; + //~^ ERROR interior mutable + //~| ERROR consider requiring `T` to be `Copy` + declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable +} + +trait Trait2 { + type CopyType: Copy; + + const SELF_2: Self; + //~^ ERROR interior mutable + //~| HELP consider requiring `Self` to be `Copy` + const ASSOC_2: Self::CopyType; // (no error) +} + +// we don't lint impl of traits, because an impl has no power to change the interface. +impl Trait for u64 { + type NonCopyType = u16; + + const ATOMIC: AtomicUsize = AtomicUsize::new(9); + const INTEGER: u64 = 10; + const STRING: String = String::new(); + const SELF: Self = 11; + const INPUT: u32 = 12; + const ASSOC: Self::NonCopyType = 13; +} + +struct Local(T, U); + +impl, U: Trait2> Local { + const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable + const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); + const T_SELF: T = T::SELF_2; + const U_SELF: U = U::SELF_2; + //~^ ERROR interior mutable + //~| HELP consider requiring `U` to be `Copy` + const T_ASSOC: T::NonCopyType = T::ASSOC; + //~^ ERROR interior mutable + //~| HELP consider requiring `>::NonCopyType` to be `Copy` + const U_ASSOC: U::CopyType = U::ASSOC_2; +} + +fn main() { + ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability + assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability + + ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutability + assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR interior mutability + + let _once = ONCE_INIT; + let _once_ref = &ONCE_INIT; //~ ERROR interior mutability + let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability + let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability + let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability + let _atomic_into_inner = ATOMIC.into_inner(); + // these should be all fine. + let _twice = (ONCE_INIT, ONCE_INIT); + let _ref_twice = &(ONCE_INIT, ONCE_INIT); + let _ref_once = &(ONCE_INIT, ONCE_INIT).0; + let _array_twice = [ONCE_INIT, ONCE_INIT]; + let _ref_array_twice = &[ONCE_INIT, ONCE_INIT]; + let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0]; + + // referencing projection is still bad. + let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability + let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability + let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability + let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability + let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability + let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability + let _ = &ATOMIC_TUPLE.2; + let _ = (&&&&ATOMIC_TUPLE).0; + let _ = (&&&&ATOMIC_TUPLE).2; + let _ = ATOMIC_TUPLE.0; + let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability + let _ = ATOMIC_TUPLE.1.into_iter(); + let _ = ATOMIC_TUPLE.2; + let _ = &{ATOMIC_TUPLE}; + + CELL.set(2); //~ ERROR interior mutability + assert_eq!(CELL.get(), 6); //~ ERROR interior mutability + + assert_eq!(INTEGER, 8); + assert!(STRING.is_empty()); + + let a = ATOMIC; + a.store(4, Ordering::SeqCst); + assert_eq!(a.load(Ordering::SeqCst), 4); + + STATIC_TUPLE.0.store(3, Ordering::SeqCst); + assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3); + assert!(STATIC_TUPLE.1.is_empty()); + + u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability + + assert_eq!(NO_ANN.to_string(), "70"); // should never lint this. +} diff --git a/tests/ui/non_copy_const.stderr b/tests/ui/non_copy_const.stderr new file mode 100644 index 000000000..388c7faba --- /dev/null +++ b/tests/ui/non_copy_const.stderr @@ -0,0 +1,275 @@ +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:10:1 + | +10 | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + | + = note: #[deny(declare_interior_mutable_const)] on by default + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:11:1 + | +11 | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:12:1 + | +12 | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:16:42 + | +16 | ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; + | ^^^^^^^^^^^^^^^^^^^^^^ +17 | } +18 | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + | ------------------------------------------ in this macro invocation + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:39:5 + | +39 | const ATOMIC: AtomicUsize; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:43:5 + | +43 | const INPUT: T; + | ^^^^^^^^^^^^^^^ + | +help: consider requiring `T` to be `Copy` + --> $DIR/non_copy_const.rs:43:18 + | +43 | const INPUT: T; + | ^ + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:46:5 + | +46 | const ASSOC: Self::NonCopyType; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider requiring `>::NonCopyType` to be `Copy` + --> $DIR/non_copy_const.rs:46:18 + | +46 | const ASSOC: Self::NonCopyType; + | ^^^^^^^^^^^^^^^^^ + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:50:5 + | +50 | const AN_INPUT: T = Self::INPUT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider requiring `T` to be `Copy` + --> $DIR/non_copy_const.rs:50:21 + | +50 | const AN_INPUT: T = Self::INPUT; + | ^ + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:16:42 + | +16 | ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; + | ^^^^^^^^^^^^^^^^^^^^^^ +... +53 | declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable + | ----------------------------------------------- in this macro invocation + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:59:5 + | +59 | const SELF_2: Self; + | ^^^^^^^^^^^^^^^^^^^ + | +help: consider requiring `Self` to be `Copy` + --> $DIR/non_copy_const.rs:59:19 + | +59 | const SELF_2: Self; + | ^^^^ + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:80:5 + | +80 | const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:83:5 + | +83 | const U_SELF: U = U::SELF_2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider requiring `U` to be `Copy` + --> $DIR/non_copy_const.rs:83:19 + | +83 | const U_SELF: U = U::SELF_2; + | ^ + +error: a const item should never be interior mutable + --> $DIR/non_copy_const.rs:86:5 + | +86 | const T_ASSOC: T::NonCopyType = T::ASSOC; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider requiring `>::NonCopyType` to be `Copy` + --> $DIR/non_copy_const.rs:86:20 + | +86 | const T_ASSOC: T::NonCopyType = T::ASSOC; + | ^^^^^^^^^^^^^^ + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:93:5 + | +93 | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^ + | + = note: #[deny(borrow_interior_mutable_const)] on by default + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:94:16 + | +94 | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability + | ^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:96:5 + | +96 | ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:97:16 + | +97 | assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:100:22 + | +100 | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability + | ^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:101:25 + | +101 | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability + | ^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:102:27 + | +102 | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability + | ^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:103:26 + | +103 | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability + | ^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:114:14 + | +114 | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:115:14 + | +115 | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:116:19 + | +116 | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:117:14 + | +117 | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:118:13 + | +118 | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:124:13 + | +124 | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:129:5 + | +129 | CELL.set(2); //~ ERROR interior mutability + | ^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:130:16 + | +130 | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability + | ^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:143:5 + | +143 | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a const item with interior mutability should not be borrowed + --> $DIR/non_copy_const.rs:144:16 + | +144 | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 31 previous errors +