From bc543d7e6c4c87f99eea4dc6217eee54cd7f18b1 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 19 Nov 2018 11:19:14 +0100 Subject: [PATCH 01/15] Allow assignments in const contexts --- src/librustc_mir/transform/qualify_consts.rs | 34 ++++++++++++++---- .../assign-to-static-within-other-static.rs | 35 +++++++++++++++++++ ...ssign-to-static-within-other-static.stderr | 8 +++++ .../const-eval/mod-static-with-const-fn.rs | 5 +-- .../mod-static-with-const-fn.stderr | 15 ++------ src/test/ui/consts/const_let_assign.rs | 12 +++++++ src/test/ui/consts/const_let_assign2.rs | 25 +++++++++++++ src/test/ui/consts/const_let_assign3.rs | 22 ++++++++++++ src/test/ui/consts/const_let_assign3.stderr | 9 +++++ 9 files changed, 143 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs create mode 100644 src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr create mode 100644 src/test/ui/consts/const_let_assign.rs create mode 100644 src/test/ui/consts/const_let_assign2.rs create mode 100644 src/test/ui/consts/const_let_assign3.rs create mode 100644 src/test/ui/consts/const_let_assign3.stderr diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 00309b0a3e905..31a0dc1494ce1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -243,13 +243,29 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { return; } + if self.tcx.features().const_let { + let mut dest = dest; + let index = loop { + match dest { + Place::Local(index) => break *index, + Place::Projection(proj) => dest = &proj.base, + Place::Promoted(..) | Place::Static(..) => { + // Catch more errors in the destination. + self.visit_place( + dest, + PlaceContext::MutatingUse(MutatingUseContext::Store), + location + ); + return; + } + } + }; + debug!("store to var {:?}", index); + self.local_qualif[index] = Some(self.qualif); + return; + } + match *dest { - Place::Local(index) if (self.mir.local_kind(index) == LocalKind::Var || - self.mir.local_kind(index) == LocalKind::Arg) && - self.tcx.sess.features_untracked().const_let => { - debug!("store to var {:?}", index); - self.local_qualif[index] = Some(self.qualif); - } Place::Local(index) if self.mir.local_kind(index) == LocalKind::Temp || self.mir.local_kind(index) == LocalKind::ReturnPointer => { debug!("store to {:?} (temp or return pointer)", index); @@ -478,6 +494,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Only allow statics (not consts) to refer to other statics. if self.mode == Mode::Static || self.mode == Mode::StaticMut { + if context.is_mutating_use() { + self.tcx.sess.span_err( + self.span, + "cannot mutate statics in the initializer of another static", + ); + } return; } self.add(Qualif::NOT_CONST); diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs new file mode 100644 index 0000000000000..5113d73b38414 --- /dev/null +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// New test for #53818: modifying static memory at compile-time is not allowed. +// The test should never compile successfully + +#![feature(const_raw_ptr_deref)] +#![feature(const_let)] + +use std::cell::UnsafeCell; + +struct Foo(UnsafeCell); + +unsafe impl Send for Foo {} +unsafe impl Sync for Foo {} + +static FOO: Foo = Foo(UnsafeCell::new(42)); + +static BAR: () = unsafe { + *FOO.0.get() = 5; +}; + +static mut FOO2: u32 = 42; +static BOO2: () = unsafe { + FOO2 = 5; +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr new file mode 100644 index 0000000000000..87f02e8e4cf7e --- /dev/null +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr @@ -0,0 +1,8 @@ +error: cannot mutate statics in the initializer of another static + --> $DIR/assign-to-static-within-other-static.rs:32:5 + | +LL | FOO2 = 5; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs index 4136a7b6a724f..600931e49a08e 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -9,7 +9,7 @@ // except according to those terms. // New test for #53818: modifying static memory at compile-time is not allowed. -// The test should never succeed. +// The test should never compile successfully #![feature(const_raw_ptr_deref)] #![feature(const_let)] @@ -27,9 +27,6 @@ fn foo() {} static BAR: () = unsafe { *FOO.0.get() = 5; - //~^ ERROR statements in statics are unstable (see issue #48821) - // This error is caused by a separate bug that the feature gate error is reported - // even though the feature gate "const_let" is active. foo(); //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index c2bba27e4d1e2..899fc24f153a5 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,18 +1,9 @@ -error[E0658]: statements in statics are unstable (see issue #48821) - --> $DIR/mod-static-with-const-fn.rs:29:5 - | -LL | *FOO.0.get() = 5; - | ^^^^^^^^^^^^^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/mod-static-with-const-fn.rs:34:5 + --> $DIR/mod-static-with-const-fn.rs:31:5 | LL | foo(); | ^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0015, E0658. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const_let_assign.rs b/src/test/ui/consts/const_let_assign.rs new file mode 100644 index 0000000000000..a3c53a451e106 --- /dev/null +++ b/src/test/ui/consts/const_let_assign.rs @@ -0,0 +1,12 @@ +// compile-pass + +#![feature(const_let)] + +struct S(i32); + +const A: () = { + let mut s = S(0); + s.0 = 1; +}; + +fn main() {} diff --git a/src/test/ui/consts/const_let_assign2.rs b/src/test/ui/consts/const_let_assign2.rs new file mode 100644 index 0000000000000..0de7396501adc --- /dev/null +++ b/src/test/ui/consts/const_let_assign2.rs @@ -0,0 +1,25 @@ +// compile-pass + +#![feature(const_let)] +#![feature(const_fn)] + +pub struct AA { + pub data: [u8; 10], +} + +impl AA { + pub const fn new() -> Self { + let mut res: AA = AA { data: [0; 10] }; + res.data[0] = 5; + res + } +} + +static mut BB: AA = AA::new(); + +fn main() { + let ptr = unsafe { &mut BB }; + for a in ptr.data.iter() { + println!("{}", a); + } +} diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs new file mode 100644 index 0000000000000..83825456b5c61 --- /dev/null +++ b/src/test/ui/consts/const_let_assign3.rs @@ -0,0 +1,22 @@ +#![feature(const_let)] +#![feature(const_fn)] + +struct S { + state: u32, +} + +impl S { + const fn foo(&mut self, x: u32) { + self.state = x; + } +} + +const FOO: S = { + let mut s = S { state: 42 }; + s.foo(3); //~ ERROR references in constants may only refer to immutable values + s +}; + +fn main() { + assert_eq!(FOO.state, 3); +} diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr new file mode 100644 index 0000000000000..7f9a953c10fe8 --- /dev/null +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -0,0 +1,9 @@ +error[E0017]: references in constants may only refer to immutable values + --> $DIR/const_let_assign3.rs:16:5 + | +LL | s.foo(3); //~ ERROR references in constants may only refer to immutable values + | ^ constants require immutable values + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0017`. From 59eff14120a067d04832142c8198f0132db2acb0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 19 Nov 2018 13:49:07 +0100 Subject: [PATCH 02/15] Also catch static mutation at evaluation time --- src/librustc/ich/impls_ty.rs | 1 + src/librustc/mir/interpret/error.rs | 3 ++ src/librustc_mir/interpret/memory.rs | 8 ++--- src/librustc_mir/transform/const_prop.rs | 1 + src/librustc_mir/transform/qualify_consts.rs | 7 ++++- .../assign-to-static-within-other-static-2.rs | 30 +++++++++++++++++++ ...ign-to-static-within-other-static-2.stderr | 9 ++++++ .../assign-to-static-within-other-static.rs | 17 ++--------- ...ssign-to-static-within-other-static.stderr | 6 ++-- src/test/ui/error-codes/E0017.rs | 1 + src/test/ui/error-codes/E0017.stderr | 10 +++++-- src/test/ui/error-codes/E0388.rs | 1 + src/test/ui/error-codes/E0388.stderr | 10 +++++-- src/test/ui/write-to-static-mut-in-static.rs | 4 +-- .../ui/write-to-static-mut-in-static.stderr | 9 ++---- 15 files changed, 82 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs create mode 100644 src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9f4..fc970400f6ccf 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -423,6 +423,7 @@ impl_stable_hash_for!( CalledClosureAsFunction, VtableForArgumentlessMethod, ModifiedConstantMemory, + ModifiedStatic, AssumptionNotHeld, InlineAsm, ReallocateNonBasePtr, diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f28aa41ed4222..5895b6cab9abd 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -276,6 +276,7 @@ pub enum EvalErrorKind<'tcx, O> { CalledClosureAsFunction, VtableForArgumentlessMethod, ModifiedConstantMemory, + ModifiedStatic, AssumptionNotHeld, InlineAsm, TypeNotPrimitive(Ty<'tcx>), @@ -380,6 +381,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> { "tried to call a vtable function without arguments", ModifiedConstantMemory => "tried to modify constant memory", + ModifiedStatic => + "tried to modify a static's initial value from another static's initializer", AssumptionNotHeld => "`assume` argument was false", InlineAsm => diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index e125927e7d273..68a91b0a3bd28 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -423,10 +423,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { if alloc.mutability == Mutability::Immutable { return err!(ModifiedConstantMemory); } - let kind = M::STATIC_KIND.expect( - "An allocation is being mutated but the machine does not expect that to happen" - ); - Ok((MemoryKind::Machine(kind), alloc.into_owned())) + match M::STATIC_KIND { + Some(kind) => Ok((MemoryKind::Machine(kind), alloc.into_owned())), + None => err!(ModifiedStatic), + } }); // Unpack the error type manually because type inference doesn't // work otherwise (and we cannot help it because `impl Trait`) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 885d70dc4304d..51327464266d5 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -197,6 +197,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { | CalledClosureAsFunction | VtableForArgumentlessMethod | ModifiedConstantMemory + | ModifiedStatic | AssumptionNotHeld // FIXME: should probably be removed and turned into a bug! call | TypeNotPrimitive(_) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 31a0dc1494ce1..1371b9a997707 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -249,7 +249,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { match dest { Place::Local(index) => break *index, Place::Projection(proj) => dest = &proj.base, - Place::Promoted(..) | Place::Static(..) => { + Place::Promoted(..) => bug!("promoteds don't exist yet during promotion"), + Place::Static(..) => { // Catch more errors in the destination. self.visit_place( dest, @@ -495,6 +496,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Only allow statics (not consts) to refer to other statics. if self.mode == Mode::Static || self.mode == Mode::StaticMut { if context.is_mutating_use() { + // this is not strictly necessary as miri will also bail out + // For interior mutability we can't really catch this statically as that + // goes through raw pointers and intermediate temporaries, so miri has + // to catch this anyway self.tcx.sess.span_err( self.span, "cannot mutate statics in the initializer of another static", diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs new file mode 100644 index 0000000000000..ef0de61d219ad --- /dev/null +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs @@ -0,0 +1,30 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// New test for #53818: modifying static memory at compile-time is not allowed. +// The test should never compile successfully + +#![feature(const_raw_ptr_deref)] +#![feature(const_let)] + +use std::cell::UnsafeCell; + +struct Foo(UnsafeCell); + +unsafe impl Send for Foo {} +unsafe impl Sync for Foo {} + +static FOO: Foo = Foo(UnsafeCell::new(42)); + +static BAR: () = unsafe { + *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr new file mode 100644 index 0000000000000..0892b05a69df2 --- /dev/null +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/assign-to-static-within-other-static-2.rs:27:5 + | +LL | *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer + | ^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs index 5113d73b38414..6f16f644eec68 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs @@ -16,20 +16,9 @@ use std::cell::UnsafeCell; -struct Foo(UnsafeCell); - -unsafe impl Send for Foo {} -unsafe impl Sync for Foo {} - -static FOO: Foo = Foo(UnsafeCell::new(42)); - -static BAR: () = unsafe { - *FOO.0.get() = 5; -}; - -static mut FOO2: u32 = 42; -static BOO2: () = unsafe { - FOO2 = 5; +static mut FOO: u32 = 42; +static BOO: () = unsafe { + FOO = 5; //~ ERROR cannot mutate statics in the initializer of another static }; fn main() {} diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr index 87f02e8e4cf7e..ca652c9df32ad 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr @@ -1,8 +1,8 @@ error: cannot mutate statics in the initializer of another static - --> $DIR/assign-to-static-within-other-static.rs:32:5 + --> $DIR/assign-to-static-within-other-static.rs:21:5 | -LL | FOO2 = 5; - | ^^^^^^^^ +LL | FOO = 5; //~ ERROR cannot mutate statics in the initializer of another static + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index c98c35a1442ad..bf400fde365be 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -14,5 +14,6 @@ const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR E0017 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| ERROR cannot borrow + //~| ERROR cannot mutate statics static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index 411b9f3139782..94a90d92d3e77 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ constants require immutable values +error: cannot mutate statics in the initializer of another static + --> $DIR/E0017.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ + error[E0017]: references in statics may only refer to immutable values --> $DIR/E0017.rs:15:39 | @@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 | ^ error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0017.rs:17:38 + --> $DIR/E0017.rs:18:38 | LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ statics require immutable values -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors occurred: E0017, E0596. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs index c002badfef64c..3203798c70958 100644 --- a/src/test/ui/error-codes/E0388.rs +++ b/src/test/ui/error-codes/E0388.rs @@ -14,6 +14,7 @@ const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR E0017 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| ERROR cannot borrow + //~| ERROR cannot mutate statics static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index d2263cd4034b8..46efda9147b6d 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ constants require immutable values +error: cannot mutate statics in the initializer of another static + --> $DIR/E0388.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ + error[E0017]: references in statics may only refer to immutable values --> $DIR/E0388.rs:15:39 | @@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 | ^ error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0388.rs:17:38 + --> $DIR/E0388.rs:18:38 | LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ statics require immutable values -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors occurred: E0017, E0596. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/write-to-static-mut-in-static.rs b/src/test/ui/write-to-static-mut-in-static.rs index 1ea74f73723b7..191f09b54ee73 100644 --- a/src/test/ui/write-to-static-mut-in-static.rs +++ b/src/test/ui/write-to-static-mut-in-static.rs @@ -12,10 +12,10 @@ pub static mut A: u32 = 0; pub static mut B: () = unsafe { A = 1; }; -//~^ ERROR statements in statics are unstable +//~^ ERROR cannot mutate statics in the initializer of another static pub static mut C: u32 = unsafe { C = 1; 0 }; -//~^ ERROR statements in statics are unstable +//~^ ERROR cannot mutate statics in the initializer of another static pub static D: u32 = D; diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index f07d240746fdf..673a71b4642f3 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -1,19 +1,14 @@ -error[E0658]: statements in statics are unstable (see issue #48821) +error: cannot mutate statics in the initializer of another static --> $DIR/write-to-static-mut-in-static.rs:14:33 | LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable -error[E0658]: statements in statics are unstable (see issue #48821) +error: cannot mutate statics in the initializer of another static --> $DIR/write-to-static-mut-in-static.rs:17:34 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. From 7d5b5ff24df9aa98e2be212b8bc7887fcc5ac16c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 19 Nov 2018 19:03:03 +0100 Subject: [PATCH 03/15] Update nll stderr files --- src/test/ui/error-codes/E0017.nll.stderr | 10 ++++++++-- src/test/ui/error-codes/E0388.nll.stderr | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/test/ui/error-codes/E0017.nll.stderr b/src/test/ui/error-codes/E0017.nll.stderr index 08708d213d3f6..8f8d87739b8cd 100644 --- a/src/test/ui/error-codes/E0017.nll.stderr +++ b/src/test/ui/error-codes/E0017.nll.stderr @@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ constants require immutable values +error: cannot mutate statics in the initializer of another static + --> $DIR/E0017.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ + error[E0017]: references in statics may only refer to immutable values --> $DIR/E0017.rs:15:39 | @@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 | ^^^^^^ cannot borrow as mutable error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0017.rs:17:38 + --> $DIR/E0017.rs:18:38 | LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ statics require immutable values -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors occurred: E0017, E0596. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0388.nll.stderr b/src/test/ui/error-codes/E0388.nll.stderr index a048374a49725..7d25d41f18b62 100644 --- a/src/test/ui/error-codes/E0388.nll.stderr +++ b/src/test/ui/error-codes/E0388.nll.stderr @@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ constants require immutable values +error: cannot mutate statics in the initializer of another static + --> $DIR/E0388.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ + error[E0017]: references in statics may only refer to immutable values --> $DIR/E0388.rs:15:39 | @@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 | ^^^^^^ cannot borrow as mutable error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0388.rs:17:38 + --> $DIR/E0388.rs:18:38 | LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 | ^^^^^^ statics require immutable values -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors occurred: E0017, E0596. For more information about an error, try `rustc --explain E0017`. From f98235ed9d8be7a6966764384a99e18ead1195e2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 20 Nov 2018 11:11:09 +0100 Subject: [PATCH 04/15] Document runtime static mutation checks --- src/librustc_mir/interpret/machine.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 57640dc48f13f..4d8f40c81301e 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -89,7 +89,8 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { Default + Clone; - /// The memory kind to use for copied statics -- or None if those are not supported. + /// The memory kind to use for copied statics -- or None if statics should not be mutated + /// and thus any such attempt will cause a `ModifiedStatic` error is raised. /// Statics are copied under two circumstances: When they are mutated, and when /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation /// that is added to the memory so that the work is not done twice. From 6bcb0d6152e0b817da7af23bdb2abf13a8b2db43 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 20 Nov 2018 11:13:19 +0100 Subject: [PATCH 05/15] Explain missing error in test --- src/test/ui/consts/const-eval/mod-static-with-const-fn.rs | 3 +++ src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs index 600931e49a08e..01fcc8307c0c1 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -27,6 +27,9 @@ fn foo() {} static BAR: () = unsafe { *FOO.0.get() = 5; + // we do not error on the above access, because that is not detectable statically. Instead, + // const evaluation will error when trying to evaluate it. Due to the error below, we never even + // attempt to const evaluate `BAR`, so we don't see the error foo(); //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index 899fc24f153a5..01ad1fc9a21b9 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,5 +1,5 @@ error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/mod-static-with-const-fn.rs:31:5 + --> $DIR/mod-static-with-const-fn.rs:34:5 | LL | foo(); | ^^^^^ From f70abe8d07023bc58cac03a989ddbd37332fa10f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 20 Nov 2018 11:33:46 +0100 Subject: [PATCH 06/15] Add sanity test for promotion and `const_let` --- src/test/ui/consts/promote_const_let.nll.stderr | 14 ++++++++++++++ src/test/ui/consts/promote_const_let.rs | 8 ++++++++ src/test/ui/consts/promote_const_let.stderr | 13 +++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 src/test/ui/consts/promote_const_let.nll.stderr create mode 100644 src/test/ui/consts/promote_const_let.rs create mode 100644 src/test/ui/consts/promote_const_let.stderr diff --git a/src/test/ui/consts/promote_const_let.nll.stderr b/src/test/ui/consts/promote_const_let.nll.stderr new file mode 100644 index 0000000000000..d8749bb5fd90b --- /dev/null +++ b/src/test/ui/consts/promote_const_let.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: `y` does not live long enough + --> $DIR/promote_const_let.rs:6:9 + | +LL | let x: &'static u32 = { + | ------------ type annotation requires that `y` is borrowed for `'static` +LL | let y = 42; +LL | &y //~ ERROR does not live long enough + | ^^ borrowed value does not live long enough +LL | }; + | - `y` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/promote_const_let.rs b/src/test/ui/consts/promote_const_let.rs new file mode 100644 index 0000000000000..1ba406a957d2d --- /dev/null +++ b/src/test/ui/consts/promote_const_let.rs @@ -0,0 +1,8 @@ +#![feature(const_let)] + +fn main() { + let x: &'static u32 = { + let y = 42; + &y //~ ERROR does not live long enough + }; +} \ No newline at end of file diff --git a/src/test/ui/consts/promote_const_let.stderr b/src/test/ui/consts/promote_const_let.stderr new file mode 100644 index 0000000000000..6bbb7495fb0dc --- /dev/null +++ b/src/test/ui/consts/promote_const_let.stderr @@ -0,0 +1,13 @@ +error[E0597]: `y` does not live long enough + --> $DIR/promote_const_let.rs:6:10 + | +LL | &y //~ ERROR does not live long enough + | ^ borrowed value does not live long enough +LL | }; + | - borrowed value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 7d96f2c4814cdf07860d31e8e8b9695eb9628972 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 20 Nov 2018 12:25:44 +0100 Subject: [PATCH 07/15] Document qualify_consts more --- src/librustc_mir/transform/qualify_consts.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 1371b9a997707..f8ecd9634579a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -247,11 +247,16 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let mut dest = dest; let index = loop { match dest { + // with `const_let` active, we treat all locals equal Place::Local(index) => break *index, + // projections are transparent for assignments + // we qualify the entire destination at once, even if just a field would have + // stricter qualification Place::Projection(proj) => dest = &proj.base, Place::Promoted(..) => bug!("promoteds don't exist yet during promotion"), Place::Static(..) => { - // Catch more errors in the destination. + // Catch more errors in the destination. `visit_place` also checks that we + // do not try to access statics from constants or try to mutate statics self.visit_place( dest, PlaceContext::MutatingUse(MutatingUseContext::Store), From 3e081c7e824eab1e5d87462e5e6a46be14c529ea Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 20 Nov 2018 12:28:24 +0100 Subject: [PATCH 08/15] Trailing newline --- src/test/ui/consts/promote_const_let.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/promote_const_let.rs b/src/test/ui/consts/promote_const_let.rs index 1ba406a957d2d..8de9b00eb111d 100644 --- a/src/test/ui/consts/promote_const_let.rs +++ b/src/test/ui/consts/promote_const_let.rs @@ -5,4 +5,4 @@ fn main() { let y = 42; &y //~ ERROR does not live long enough }; -} \ No newline at end of file +} From 37fcd5cad5c314632aede576ae5fbbb1c3ede228 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 20 Nov 2018 12:29:05 +0100 Subject: [PATCH 09/15] Grammar nit --- src/librustc_mir/interpret/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 4d8f40c81301e..dd247a96fa48a 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -90,7 +90,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { Clone; /// The memory kind to use for copied statics -- or None if statics should not be mutated - /// and thus any such attempt will cause a `ModifiedStatic` error is raised. + /// and thus any such attempt will cause a `ModifiedStatic` error to be raised. /// Statics are copied under two circumstances: When they are mutated, and when /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation /// that is added to the memory so that the work is not done twice. From 301ce8b2aa6156ae8dc535ca234e95b04e7c4e4b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 21 Nov 2018 10:37:18 +0100 Subject: [PATCH 10/15] Properly assign to aggregate fields --- src/librustc_mir/transform/qualify_consts.rs | 7 ++++++- src/test/ui/consts/partial_qualif.rs | 11 +++++++++++ src/test/ui/consts/partial_qualif.stderr | 9 +++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/partial_qualif.rs create mode 100644 src/test/ui/consts/partial_qualif.stderr diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f8ecd9634579a..51e590fe29291 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -267,7 +267,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } }; debug!("store to var {:?}", index); - self.local_qualif[index] = Some(self.qualif); + match &mut self.local_qualif[index] { + // update + Some(ref mut qualif) => *qualif = *qualif | self.qualif, + // or insert + qualif @ None => *qualif = Some(self.qualif), + } return; } diff --git a/src/test/ui/consts/partial_qualif.rs b/src/test/ui/consts/partial_qualif.rs new file mode 100644 index 0000000000000..bb3fc92d4fb4e --- /dev/null +++ b/src/test/ui/consts/partial_qualif.rs @@ -0,0 +1,11 @@ +#![feature(const_let)] + +use std::cell::Cell; + +const FOO: &(Cell, bool) = { + let mut a = (Cell::new(0), false); + a.1 = true; // resets `qualif(a)` to `qualif(true)` + &{a} //~ ERROR cannot borrow a constant which may contain interior mutability +}; + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/consts/partial_qualif.stderr b/src/test/ui/consts/partial_qualif.stderr new file mode 100644 index 0000000000000..d695f64e2c3b5 --- /dev/null +++ b/src/test/ui/consts/partial_qualif.stderr @@ -0,0 +1,9 @@ +error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead + --> $DIR/partial_qualif.rs:8:5 + | +LL | &{a} //~ ERROR cannot borrow a constant which may contain interior mutability + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0492`. From 3c290a5326755d5f978caf66cfd61b05652169d5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 21 Nov 2018 10:42:40 +0100 Subject: [PATCH 11/15] Ensure assignments don't allow skipping projection checks --- src/librustc_mir/transform/qualify_consts.rs | 11 ++++++++++- src/test/ui/consts/projection_qualif.rs | 14 ++++++++++++++ src/test/ui/consts/projection_qualif.stderr | 18 ++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/projection_qualif.rs create mode 100644 src/test/ui/consts/projection_qualif.stderr diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 51e590fe29291..571fe99897058 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -252,7 +252,16 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // projections are transparent for assignments // we qualify the entire destination at once, even if just a field would have // stricter qualification - Place::Projection(proj) => dest = &proj.base, + Place::Projection(proj) => { + // Catch more errors in the destination. `visit_place` also checks various + // projection rules like union field access and raw pointer deref + self.visit_place( + dest, + PlaceContext::MutatingUse(MutatingUseContext::Store), + location + ); + dest = &proj.base; + }, Place::Promoted(..) => bug!("promoteds don't exist yet during promotion"), Place::Static(..) => { // Catch more errors in the destination. `visit_place` also checks that we diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs new file mode 100644 index 0000000000000..4806fecee4319 --- /dev/null +++ b/src/test/ui/consts/projection_qualif.rs @@ -0,0 +1,14 @@ +#![feature(const_let)] + +use std::cell::Cell; + +const FOO: &u32 = { + let mut a = 42; + { + let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values + unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants + } + &{a} +}; + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr new file mode 100644 index 0000000000000..d5252f199beac --- /dev/null +++ b/src/test/ui/consts/projection_qualif.stderr @@ -0,0 +1,18 @@ +error[E0017]: references in constants may only refer to immutable values + --> $DIR/projection_qualif.rs:8:27 + | +LL | let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values + | ^^^^^^ constants require immutable values + +error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911) + --> $DIR/projection_qualif.rs:9:18 + | +LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants + | ^^^^^^ + | + = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors occurred: E0017, E0658. +For more information about an error, try `rustc --explain E0017`. From 42a3f730c75c4e4b62eb58d4e09a8ec833e13804 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 21 Nov 2018 11:13:49 +0100 Subject: [PATCH 12/15] Tidy --- src/test/ui/consts/partial_qualif.rs | 2 +- src/test/ui/consts/projection_qualif.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/consts/partial_qualif.rs b/src/test/ui/consts/partial_qualif.rs index bb3fc92d4fb4e..7cf9ee1d94b0e 100644 --- a/src/test/ui/consts/partial_qualif.rs +++ b/src/test/ui/consts/partial_qualif.rs @@ -8,4 +8,4 @@ const FOO: &(Cell, bool) = { &{a} //~ ERROR cannot borrow a constant which may contain interior mutability }; -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index 4806fecee4319..34e8eaba9f28f 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -11,4 +11,4 @@ const FOO: &u32 = { &{a} }; -fn main() {} \ No newline at end of file +fn main() {} From e05b61ccd8fcb4bb4fd12085fc13522b940e7618 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 21 Nov 2018 11:47:16 +0100 Subject: [PATCH 13/15] Fix a comment --- src/test/ui/consts/partial_qualif.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/partial_qualif.rs b/src/test/ui/consts/partial_qualif.rs index 7cf9ee1d94b0e..4ce41f80f82c8 100644 --- a/src/test/ui/consts/partial_qualif.rs +++ b/src/test/ui/consts/partial_qualif.rs @@ -4,7 +4,7 @@ use std::cell::Cell; const FOO: &(Cell, bool) = { let mut a = (Cell::new(0), false); - a.1 = true; // resets `qualif(a)` to `qualif(true)` + a.1 = true; // sets `qualif(a)` to `qualif(a) | qualif(true)` &{a} //~ ERROR cannot borrow a constant which may contain interior mutability }; From 22aebd57c8ed5344260059abebbb938683ab4d91 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 21 Nov 2018 11:47:44 +0100 Subject: [PATCH 14/15] Add regression test for overwriting qualifs by assignment --- src/test/ui/consts/qualif_overwrite.rs | 13 +++++++++++++ src/test/ui/consts/qualif_overwrite.stderr | 9 +++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/consts/qualif_overwrite.rs create mode 100644 src/test/ui/consts/qualif_overwrite.stderr diff --git a/src/test/ui/consts/qualif_overwrite.rs b/src/test/ui/consts/qualif_overwrite.rs new file mode 100644 index 0000000000000..65e182945bf79 --- /dev/null +++ b/src/test/ui/consts/qualif_overwrite.rs @@ -0,0 +1,13 @@ +// compile-pass + +#![feature(const_let)] + +use std::cell::Cell; + +const FOO: &Option> = { + let mut a = Some(Cell::new(0)); + a = None; // resets `qualif(a)` to `qualif(None)` + &{a} +}; + +fn main() {} diff --git a/src/test/ui/consts/qualif_overwrite.stderr b/src/test/ui/consts/qualif_overwrite.stderr new file mode 100644 index 0000000000000..b24c0fa70f063 --- /dev/null +++ b/src/test/ui/consts/qualif_overwrite.stderr @@ -0,0 +1,9 @@ +error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead + --> $DIR/qualif_overwrite.rs:8:5 + | +LL | &{a} //~ ERROR cannot borrow a constant which may contain interior mutability + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0492`. From 6db8c6c6d9fd1f8226b3afd9e18c6fb3cd2f1176 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 21 Nov 2018 11:58:28 +0100 Subject: [PATCH 15/15] Explain why we do not overwrite qualification of locals --- src/librustc_mir/transform/qualify_consts.rs | 7 +++++-- src/test/ui/consts/qualif_overwrite.rs | 10 ++++++---- src/test/ui/consts/qualif_overwrite.stderr | 2 +- src/test/ui/consts/qualif_overwrite_2.rs | 13 +++++++++++++ src/test/ui/consts/qualif_overwrite_2.stderr | 9 +++++++++ 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/consts/qualif_overwrite_2.rs create mode 100644 src/test/ui/consts/qualif_overwrite_2.stderr diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 571fe99897058..399c6dbcb7ca6 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -277,9 +277,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { }; debug!("store to var {:?}", index); match &mut self.local_qualif[index] { - // update + // this is overly restrictive, because even full assignments do not clear the qualif + // While we could special case full assignments, this would be inconsistent with + // aggregates where we overwrite all fields via assignments, which would not get + // that feature. Some(ref mut qualif) => *qualif = *qualif | self.qualif, - // or insert + // insert new qualification qualif @ None => *qualif = Some(self.qualif), } return; diff --git a/src/test/ui/consts/qualif_overwrite.rs b/src/test/ui/consts/qualif_overwrite.rs index 65e182945bf79..806a74ee4530b 100644 --- a/src/test/ui/consts/qualif_overwrite.rs +++ b/src/test/ui/consts/qualif_overwrite.rs @@ -1,13 +1,15 @@ -// compile-pass - #![feature(const_let)] use std::cell::Cell; +// this is overly conservative. The reset to `None` should clear `a` of all qualifications +// while we could fix this, it would be inconsistent with `qualif_overwrite_2.rs`. +// We can fix this properly in the future by allowing constants that do not depend on generics +// to be checked by an analysis on the final value instead of looking at the body. const FOO: &Option> = { let mut a = Some(Cell::new(0)); - a = None; // resets `qualif(a)` to `qualif(None)` - &{a} + a = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` + &{a} //~ ERROR cannot borrow a constant which may contain interior mutability }; fn main() {} diff --git a/src/test/ui/consts/qualif_overwrite.stderr b/src/test/ui/consts/qualif_overwrite.stderr index b24c0fa70f063..4fac64bf8063f 100644 --- a/src/test/ui/consts/qualif_overwrite.stderr +++ b/src/test/ui/consts/qualif_overwrite.stderr @@ -1,5 +1,5 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/qualif_overwrite.rs:8:5 + --> $DIR/qualif_overwrite.rs:12:5 | LL | &{a} //~ ERROR cannot borrow a constant which may contain interior mutability | ^^^^ diff --git a/src/test/ui/consts/qualif_overwrite_2.rs b/src/test/ui/consts/qualif_overwrite_2.rs new file mode 100644 index 0000000000000..29557a3da4781 --- /dev/null +++ b/src/test/ui/consts/qualif_overwrite_2.rs @@ -0,0 +1,13 @@ +#![feature(const_let)] + +use std::cell::Cell; + +// const qualification is not smart enough to know about fields and always assumes that there might +// be other fields that caused the qualification +const FOO: &Option> = { + let mut a = (Some(Cell::new(0)),); + a.0 = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` + &{a.0} //~ ERROR cannot borrow a constant which may contain interior mutability +}; + +fn main() {} diff --git a/src/test/ui/consts/qualif_overwrite_2.stderr b/src/test/ui/consts/qualif_overwrite_2.stderr new file mode 100644 index 0000000000000..181b728c7b76f --- /dev/null +++ b/src/test/ui/consts/qualif_overwrite_2.stderr @@ -0,0 +1,9 @@ +error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead + --> $DIR/qualif_overwrite_2.rs:10:5 + | +LL | &{a.0} //~ ERROR cannot borrow a constant which may contain interior mutability + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0492`.