Uh oh!
There was an error while loading. Please reload this page.
Bypass const_item_mutation if const's type has Drop impl - #77251
Conversation
Aaron1011
commented
Sep 27, 2020
I'm not convinced that this is a good idea. The point of If anything, However, I think it would be reasonable to add a note to the warning message if the type has a destructor, so that the user is away that deleting the statement may cause unexpected changes in behavior. |
Let me clarify the reason I came across this. I am using assignments for a global static configuration of a library, as in e.g. Here is a simplified setup to give you the flavor (actual implementation is somewhat different): pubmod thelibrary {use lazy_static::lazy_static;use std::ptr;use std::sync::atomic::{AtomicPtr,Ordering};use std::sync::Mutex;pubstructOptions{pubinclude_prefix:&'staticstr,}lazy_static!{static ref INCLUDE_PREFIX:Mutex<&'staticstr> = Mutex::new(env!("CARGO_CRATE_NAME"));}implOptions{fncurrent() -> Self{Options{include_prefix:*INCLUDE_PREFIX.lock().unwrap(),}}}use private::Cfg;pubconstCFG:Cfg = Cfg{options:AtomicPtr::new(ptr::null_mut()),};mod private {usesuper::*;pubstructCfg{pub(super)options:AtomicPtr<Options>,}}impl std::ops::DerefforCfg{typeTarget = Options;fnderef(&self) -> &Self::Target{let options = Box::into_raw(Box::new(Options::current()));let prev = self.options.compare_and_swap(ptr::null_mut(), options,Ordering::Relaxed);if !prev.is_null(){// compare_and_swap did nothing.let _ = unsafe{Box::from_raw(options)};panic!();}unsafe{&*options }}}impl std::ops::DerefMutforCfg{fnderef_mut(&mutself) -> &mutSelf::Target{let options = self.options.get_mut();if !options.is_null(){panic!();}*options = Box::into_raw(Box::new(Options::current()));unsafe{&mut**options }}}implDropforCfg{fndrop(&mutself){let options = *self.options.get_mut();ifletSome(options) = unsafe{ options.as_mut()}{*INCLUDE_PREFIX.lock().unwrap() = options.include_prefix;let _ = unsafe{Box::from_raw(options)};}}}}use thelibrary::CFG;fnmain(){CFG.include_prefix = "path/to";println!("{:?}",CFG.include_prefix);}
I think the snippet above shows it has exactly the effect the person should expect. The write is observable to subsequent reads of the const. |
Aaron1011
commented
Sep 27, 2020
Wow, that's quite the API 😄 It looks like the lint is firing for the implicit I'm worried that a blanket suppression of this lint for all types with drop glue will cause many false negatives. I think it would make more sense to have a per-item opt out, which would indicate that any mutation actually has some side effect. @dtolnay Would something like |
dtolnay
commented
Sep 27, 2020
It has been beneficial for this library because it very deliberately triggers "okay I am writing to a global (though safely)" neurons, which
Right now that would be slightly less good for me because it would imply having to do rustc version detection for whether const_mutation_allowed is supported in the current compiler, but it would work, and I sympathize with the concern about false negatives. As a new user-facing attribute I guess that would need to go through FCP (compiler team? lang team?). If so, and if it doesn't make the next beta cutoff which is happening next week, I would ask that we consider the approach in the PR in the interim until const_mutation_allowed is landed (and not feature gated). |
That sounds fine to me. I'll work on an MCP. |
To clarify, as implemented in the PR this is not bypassing for all types with drop glue. It's only for types that specifically have their own Drop impl. Something with compiler-generated drop glue but not a Drop impl would still warn. structLog{s:String}constLOG:Log = Log{s:String::new()};fnmain(){LOG.s = "~~~".to_owned();//~attempting to modify a `const` item} |
bugaevc
commented
Sep 27, 2020
Would a warning still get emitted in the constVEC:Vec<i32> = Vec::new();fnmain(){VEC.push(42);println!("{:?}",VEC);} |
dtolnay
commented
Sep 28, 2020
bugaevc
commented
Sep 28, 2020
What I'm saying is it would be unfortunate to lose the warning in the So perhaps there could be a better heuristic to detect cases like yours above, while also keeping a warning for simple cases that happen to have a |
This comment has been minimized.
This comment has been minimized.
adt_destructor by default also validates the Drop impl using
dropck::check_drop_impl, which contains an expect_local(). This
leads to ICE in check_const_item_mutation if the const's type is
not a local type.
thread 'rustc' panicked at 'DefId::expect_local: `DefId(5:4805 ~ alloc[d7e9]::vec::{impl#50})` isn't local', compiler/rustc_span/src/def_id.rs:174:43
stack backtrace:
0: rust_begin_unwind
1: rustc_span::def_id::DefId::expect_local::{{closure}}
2: rustc_typeck::check::dropck::check_drop_impl
3: rustc_middle::ty::util::<impl rustc_middle::ty::context::TyCtxt>::calculate_dtor::{{closure}}
4: rustc_middle::ty::trait_def::<impl rustc_middle::ty::context::TyCtxt>::for_each_relevant_impl
5: rustc_middle::ty::util::<impl rustc_middle::ty::context::TyCtxt>::calculate_dtor
6: rustc_typeck::check::adt_destructor
7: rustc_middle::ty::query::<impl rustc_query_system::query::config::QueryAccessors<rustc_middle::ty::context::TyCtxt> for rustc_middle::ty::query::queries::adt_destructor>::compute
8: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task_impl
9: rustc_query_system::query::plumbing::get_query_impl
10: rustc_mir::transform::check_const_item_mutation::ConstMutationChecker::is_const_item_without_destructordtolnay
commented
Oct 1, 2020
|
dtolnay
commented
Oct 1, 2020
@bugaevc: I updated the PR to still warn in the case of a |
| let def_id = self.is_const_item(local)?; | ||
| let mut any_dtor = |_tcx, _def_id| Ok(()); | ||
| // We avoid linting mutation of a const item if the const's type has a |
There was a problem hiding this comment.
Can you open an issue to track removing this (conditional on having a stable attribute to suppress the lint for a particular const item), and add a FIXME?
Aaron1011
commented
Oct 1, 2020
@dtolnay: I wasn't able to come up with a good design for an attribute to suppress this. There are similar lints that I'd like to create/uplift in the future (e.g. const items with interior mutability), and it would be annoying to introduce a single-use attribute for each of them. r=me with the comment addressed, so that this can be beta-backported. |
dtolnay
commented
Oct 1, 2020
@bors r=Aaron1011 |
bors
commented
Oct 1, 2020
📌 Commit 804d159 has been approved by |
…as-schievink Rollup of 8 pull requests Successful merges: - rust-lang#75377 (Fix Debug implementations of some of the HashMap and BTreeMap iterator types) - rust-lang#76107 (Write manifest for MAJOR.MINOR channel to enable rustup convenience) - rust-lang#76745 (Move Wrapping<T> ui tests into library) - rust-lang#77182 (Add missing examples for Fd traits) - rust-lang#77251 (Bypass const_item_mutation if const's type has Drop impl) - rust-lang#77264 (Only use LOCAL_{STDOUT,STDERR} when set_{print/panic} is used. ) - rust-lang#77421 (Revert "resolve: Avoid "self-confirming" import resolutions in one more case") - rust-lang#77452 (Permit ty::Bool in const generics for v0 mangling) Failed merges: r? `@ghost`
Follow-up to #75573. This PR disables the const_item_mutation lint in cases that the const has a Drop impl which observes the mutation.
r? @Aaron1011