From f2ae7b78d63695c1b9ff7bdf4079c7a02e77f73e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 00:22:12 +0100 Subject: [PATCH 01/23] Allow calling `const unsafe fn` in `const fn` behind a feature gate --- src/librustc/mir/mod.rs | 3 +- src/librustc/ty/constness.rs | 4 +- src/librustc_mir/build/mod.rs | 9 ++- src/librustc_mir/transform/check_unsafety.rs | 81 +++++++++++++------ src/libsyntax/feature_gate.rs | 3 + .../min_const_fn/min_const_fn_unsafe.rs | 2 + .../min_const_fn/min_const_fn_unsafe.stderr | 14 ++-- .../min_const_fn_unsafe_feature_gate.rs | 56 +++++++++++++ .../min_const_fn_unsafe_feature_gate.stderr | 59 ++++++++++++++ 9 files changed, 194 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 368f83eb61127..c0581121efa1c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2770,7 +2770,8 @@ impl Location { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UnsafetyViolationKind { General, - /// unsafety is not allowed at all in min const fn + /// Right now function calls to `const unsafe fn` are the only permitted unsafe operation in + /// const fn. Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations MinConstFn, ExternStatic(ast::NodeId), BorrowPacked(ast::NodeId), diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index e32913b8905b7..f067a125c5dc9 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } // in order for a libstd function to be considered min_const_fn // it needs to be stable and have no `rustc_const_unstable` attribute - match self.lookup_stability(def_id) { + self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) { // stable functions with unstable const fn aren't `min_const_fn` Some(&attr::Stability { const_stability: Some(_), .. }) => false, // unstable functions don't need to conform @@ -66,7 +66,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } } else { // users enabling the `const_fn` feature gate can do what they want - !self.features().const_fn + self.is_const_fn_raw(def_id) && !self.features().const_fn } } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index d95a74be77696..cc927df6350bd 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -91,8 +91,9 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t // types/lifetimes replaced) let fn_hir_id = tcx.hir.node_to_hir_id(id); let fn_sig = cx.tables().liberated_fn_sigs()[fn_hir_id].clone(); + let fn_def_id = tcx.hir.local_def_id(id); - let ty = tcx.type_of(tcx.hir.local_def_id(id)); + let ty = tcx.type_of(fn_def_id); let mut abi = fn_sig.abi; let implicit_argument = match ty.sty { ty::Closure(..) => { @@ -113,6 +114,12 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t hir::Unsafety::Normal => Safety::Safe, hir::Unsafety::Unsafe => Safety::FnUnsafe, }; + let safety = if implicit_argument.is_none() && tcx.is_min_const_fn(fn_def_id) { + // the body of `const unsafe fn`s is treated like the body of safe `const fn`s + Safety::Safe + } else { + safety + }; let body = tcx.hir.body(body_id); let explicit_arguments = diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 3404772f8255f..d096bb32d9586 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -34,6 +34,7 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> { source_info: SourceInfo, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, + /// mark an `unsafe` block as used, so we don't lint it used_unsafe: FxHashSet, inherited_blocks: Vec<(ast::NodeId, bool)>, } @@ -93,7 +94,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if let hir::Unsafety::Unsafe = sig.unsafety() { self.require_unsafe("call to unsafe function", "consult the function's documentation for information on how to avoid \ - undefined behavior") + undefined behavior", UnsafetyViolationKind::MinConstFn) } } } @@ -121,7 +122,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { StatementKind::InlineAsm { .. } => { self.require_unsafe("use of inline assembly", - "inline assembly is entirely unchecked and can cause undefined behavior") + "inline assembly is entirely unchecked and can cause undefined behavior", + UnsafetyViolationKind::General) }, } self.super_statement(block, statement, location); @@ -189,7 +191,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.require_unsafe("dereference of raw pointer", "raw pointers may be NULL, dangling or unaligned; they can violate \ aliasing rules and cause data races: all of these are undefined \ - behavior") + behavior", UnsafetyViolationKind::General) } ty::Adt(adt, _) => { if adt.is_union() { @@ -212,14 +214,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { "assignment to non-`Copy` union field", "the previous content of the field will be dropped, which \ causes undefined behavior if the field was not properly \ - initialized") + initialized", UnsafetyViolationKind::General) } else { // write to non-move union, safe } } else { self.require_unsafe("access to union field", "the field may not be properly initialized: using \ - uninitialized data will cause undefined behavior") + uninitialized data will cause undefined behavior", + UnsafetyViolationKind::General) } } } @@ -237,7 +240,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) { self.require_unsafe("use of mutable static", "mutable statics can be mutated by multiple threads: aliasing violations \ - or data races will cause undefined behavior"); + or data races will cause undefined behavior", + UnsafetyViolationKind::General); } else if self.tcx.is_foreign_item(def_id) { let source_info = self.source_info; let lint_root = @@ -260,45 +264,70 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { - fn require_unsafe(&mut self, - description: &'static str, - details: &'static str) - { + fn require_unsafe( + &mut self, + description: &'static str, + details: &'static str, + kind: UnsafetyViolationKind, + ) { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, description: Symbol::intern(description).as_interned_str(), details: Symbol::intern(details).as_interned_str(), - kind: UnsafetyViolationKind::General, + kind, }], &[]); } fn register_violations(&mut self, violations: &[UnsafetyViolation], unsafe_blocks: &[(ast::NodeId, bool)]) { - if self.min_const_fn { - for violation in violations { - let mut violation = violation.clone(); - violation.kind = UnsafetyViolationKind::MinConstFn; - if !self.violations.contains(&violation) { - self.violations.push(violation) - } - } - } - let within_unsafe = match self.source_scope_local_data[self.source_info.scope].safety { - Safety::Safe => { + let safety = self.source_scope_local_data[self.source_info.scope].safety; + let within_unsafe = match (safety, self.min_const_fn) { + // FIXME: erring on the safe side here and disallowing builtin unsafety in const fn + (Safety::BuiltinUnsafe, true) | + // `unsafe` blocks are required even in `const unsafe fn` + (Safety::FnUnsafe, true) | + // `unsafe` blocks are required in safe code + (Safety::Safe, _) => { for violation in violations { - if !self.violations.contains(violation) { - self.violations.push(violation.clone()) + let mut violation = violation.clone(); + if self.min_const_fn { + // overwrite unsafety violation in const fn with a single hard error kind + violation.kind = UnsafetyViolationKind::MinConstFn; + } else if let UnsafetyViolationKind::MinConstFn = violation.kind { + // outside of const fns we treat `MinConstFn` and `General` the same + violation.kind = UnsafetyViolationKind::General; + } + if !self.violations.contains(&violation) { + self.violations.push(violation) } } false } - Safety::BuiltinUnsafe | Safety::FnUnsafe => true, - Safety::ExplicitUnsafe(node_id) => { + (Safety::BuiltinUnsafe, false) | (Safety::FnUnsafe, false) => true, + (Safety::ExplicitUnsafe(node_id), _) => { if !violations.is_empty() { self.used_unsafe.insert(node_id); } + // only some unsafety is allowed in const fn + if self.min_const_fn { + for violation in violations { + match violation.kind { + // these are allowed + UnsafetyViolationKind::MinConstFn + if self.tcx.sess.features_untracked().min_const_unsafe_fn => {}, + _ => { + let mut violation = violation.clone(); + // overwrite unsafety violation in const fn with a hard error + violation.kind = UnsafetyViolationKind::MinConstFn; + if !self.violations.contains(&violation) { + self.violations.push(violation) + } + }, + } + } + } true } }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fac7ff2bf342d..026b159f80f9a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -492,6 +492,9 @@ declare_features! ( // `extern crate self as foo;` puts local crate root into extern prelude under name `foo`. (active, extern_crate_self, "1.31.0", Some(56409), None), + + // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + (active, min_const_unsafe_fn, "1.31.0", Some(55607), None), ); declare_features! ( diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index 67332c6d2cfb2..7a84992e14b36 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// gate-test-min_const_unsafe_fn + // ok const unsafe fn foo4() -> i32 { 42 } const unsafe fn foo5() -> *const T { 0 as *const T } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 8cff0d491d8a4..17cba8569c148 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,5 +1,5 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe.rs:27:51 + --> $DIR/min_const_fn_unsafe.rs:29:51 | LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn | ^^ @@ -7,7 +7,7 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe.rs:34:5 + --> $DIR/min_const_fn_unsafe.rs:36:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn = help: add #![feature(const_fn_union)] to the crate attributes to enable error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:19:14 + --> $DIR/min_const_fn_unsafe.rs:21:14 | LL | unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn | ^^^^^^ call to unsafe function @@ -23,7 +23,7 @@ LL | unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const = note: consult the function's documentation for information on how to avoid undefined behavior error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:22:14 + --> $DIR/min_const_fn_unsafe.rs:24:14 | LL | unsafe { foo5::() } //~ ERROR unsafe operations are not allowed in const fn | ^^^^^^^^^^^^^^^^ call to unsafe function @@ -31,7 +31,7 @@ LL | unsafe { foo5::() } //~ ERROR unsafe operations are not allowed = note: consult the function's documentation for information on how to avoid undefined behavior error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:25:14 + --> $DIR/min_const_fn_unsafe.rs:27:14 | LL | unsafe { foo6::>>() } //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function @@ -39,7 +39,7 @@ LL | unsafe { foo6::>>() } //~ ERROR not allowed in = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:27:51 + --> $DIR/min_const_fn_unsafe.rs:29:51 | LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn | ^^ dereference of raw pointer @@ -47,7 +47,7 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:34:5 + --> $DIR/min_const_fn_unsafe.rs:36:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs new file mode 100644 index 0000000000000..f3e85ebe5f60b --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs @@ -0,0 +1,56 @@ +// 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. + +#![feature(min_const_unsafe_fn)] + +// ok +const unsafe fn foo4() -> i32 { 42 } +const unsafe fn foo5() -> *const T { 0 as *const T } +const unsafe fn foo6() -> *mut T { 0 as *mut T } +const fn no_unsafe() { unsafe {} } + +const fn foo8() -> i32 { + unsafe { foo4() } +} +const fn foo9() -> *const String { + unsafe { foo5::() } +} +const fn foo10() -> *const Vec> { + unsafe { foo6::>>() } +} +const unsafe fn foo8_3() -> i32 { + unsafe { foo4() } +} +const unsafe fn foo9_3() -> *const String { + unsafe { foo5::() } +} +const unsafe fn foo10_3() -> *const Vec> { + unsafe { foo6::>>() } +} +// not ok +const unsafe fn foo8_2() -> i32 { + foo4() //~ ERROR not allowed in const fn +} +const unsafe fn foo9_2() -> *const String { + foo5::() //~ ERROR not allowed in const fn +} +const unsafe fn foo10_2() -> *const Vec> { + foo6::>>() //~ ERROR not allowed in const fn +} +const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +//~^ dereferencing raw pointers in constant functions + +fn main() {} + +const unsafe fn no_union() { + union Foo { x: (), y: () } + Foo { x: () }.y //~ ERROR not allowed in const fn + //~^ unions in const fn +} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr new file mode 100644 index 0000000000000..78bf99b0a4d99 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr @@ -0,0 +1,59 @@ +error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) + --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 + | +LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn + | ^^ + | + = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable + +error[E0658]: unions in const fn are unstable (see issue #51909) + --> $DIR/min_const_fn_unsafe_feature_gate.rs:54:5 + | +LL | Foo { x: () }.y //~ ERROR not allowed in const fn + | ^^^^^^^^^^^^^^^ + | + = help: add #![feature(const_fn_union)] to the crate attributes to enable + +error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn + --> $DIR/min_const_fn_unsafe_feature_gate.rs:39:5 + | +LL | foo4() //~ ERROR not allowed in const fn + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn + --> $DIR/min_const_fn_unsafe_feature_gate.rs:42:5 + | +LL | foo5::() //~ ERROR not allowed in const fn + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn + --> $DIR/min_const_fn_unsafe_feature_gate.rs:45:5 + | +LL | foo6::>>() //~ ERROR not allowed in const fn + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn + --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 + | +LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn + | ^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: access to union field is unsafe and unsafe operations are not allowed in const fn + --> $DIR/min_const_fn_unsafe_feature_gate.rs:54:5 + | +LL | Foo { x: () }.y //~ ERROR not allowed in const fn + | ^^^^^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. From 906a49eef27c927ff73ed5712d5cd663b06d8963 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 11:09:52 +0100 Subject: [PATCH 02/23] Document unsafe rules with comments and `bug!` calls --- src/librustc_mir/transform/check_unsafety.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index d096bb32d9586..0547e4476cbe4 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -284,10 +284,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { unsafe_blocks: &[(ast::NodeId, bool)]) { let safety = self.source_scope_local_data[self.source_info.scope].safety; let within_unsafe = match (safety, self.min_const_fn) { - // FIXME: erring on the safe side here and disallowing builtin unsafety in const fn + // Erring on the safe side, pun intended (Safety::BuiltinUnsafe, true) | - // `unsafe` blocks are required even in `const unsafe fn` - (Safety::FnUnsafe, true) | + // mir building encodes const fn bodies as safe, even for `const unsafe fn` + (Safety::FnUnsafe, true) => bug!("const unsafe fn body treated as inherently unsafe"), // `unsafe` blocks are required in safe code (Safety::Safe, _) => { for violation in violations { @@ -305,8 +305,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } false } + // regular `unsafe` function bodies allow unsafe without additional unsafe blocks (Safety::BuiltinUnsafe, false) | (Safety::FnUnsafe, false) => true, (Safety::ExplicitUnsafe(node_id), _) => { + // mark unsafe block as used if there are any unsafe operations inside if !violations.is_empty() { self.used_unsafe.insert(node_id); } @@ -316,6 +318,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { match violation.kind { // these are allowed UnsafetyViolationKind::MinConstFn + // if `#![feature(min_const_unsafe_fn)]` is active if self.tcx.sess.features_untracked().min_const_unsafe_fn => {}, _ => { let mut violation = violation.clone(); From cc3470ce3b0ef74eab0f46d865d4d6021911b284 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 12:08:19 +0100 Subject: [PATCH 03/23] Add test for dereferencing raw pointers and immediately referencing again --- .../min_const_fn_unsafe_feature_gate.rs | 3 +++ .../min_const_fn_unsafe_feature_gate.stderr | 22 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs index f3e85ebe5f60b..b66460d64089b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs @@ -47,6 +47,9 @@ const unsafe fn foo10_2() -> *const Vec> { const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn //~^ dereferencing raw pointers in constant functions +const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn +//~^ dereferencing raw pointers in constant functions + fn main() {} const unsafe fn no_union() { diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr index 78bf99b0a4d99..d88ed1a5ad2cf 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr @@ -6,8 +6,16 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable +error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) + --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 + | +LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn + | ^^^ + | + = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable + error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:54:5 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:57:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ @@ -46,14 +54,22 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior +error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn + --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 + | +LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn + | ^^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:54:5 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:57:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0658`. From 02b22323f129446c9e2255d0eeab6c7ab17aac52 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 13:03:05 +0100 Subject: [PATCH 04/23] Make sure the initialization of constrained int range newtypes is unsafe --- src/libcore/lib.rs | 1 + src/libcore/nonzero.rs | 10 +++- src/libcore/num/mod.rs | 4 +- src/libcore/ptr.rs | 14 +++--- src/librustc_mir/transform/check_unsafety.rs | 16 ++++++- .../min_const_unsafe_fn_libstd_stability.rs | 47 +++++++++++++++++++ ...in_const_unsafe_fn_libstd_stability.stderr | 26 ++++++++++ .../min_const_unsafe_fn_libstd_stability2.rs | 43 +++++++++++++++++ ...n_const_unsafe_fn_libstd_stability2.stderr | 20 ++++++++ 9 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 726e891df0ccf..d070160609d29 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -93,6 +93,7 @@ #![feature(never_type)] #![feature(nll)] #![feature(exhaustive_patterns)] +#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 436cd1fc05728..22d93a5301efa 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -15,10 +15,18 @@ use ops::{CoerceUnsized, DispatchFromDyn}; /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. #[rustc_layout_scalar_valid_range_start(1)] -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] pub(crate) struct NonZero(pub(crate) T); +// Do not call `T::clone` as theoretically it could turn the field into `0` +// invalidating `NonZero`'s invariant. +impl Clone for NonZero { + fn clone(&self) -> Self { + unsafe { NonZero(self.0) } + } +} + impl, U> CoerceUnsized> for NonZero {} impl, U> DispatchFromDyn> for NonZero {} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 805be431328e2..7f5d596b220b9 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -70,7 +70,7 @@ assert_eq!(size_of::>(), size_of::<", st #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { - $Ty(NonZero(n)) + $Ty(unsafe { NonZero(n) }) } /// Create a non-zero if the given value is not zero. @@ -78,7 +78,7 @@ assert_eq!(size_of::>(), size_of::<", st #[inline] pub fn new(n: $Int) -> Option { if n != 0 { - Some($Ty(NonZero(n))) + Some($Ty(unsafe { NonZero(n) })) } else { None } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d3a74ed2a6856..a07c7260f712c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2759,7 +2759,7 @@ impl Unique { /// Creates a new `Unique` if `ptr` is non-null. pub fn new(ptr: *mut T) -> Option { if !ptr.is_null() { - Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData }) + Some(Unique { pointer: unsafe { NonZero(ptr as _) }, _marker: PhantomData }) } else { None } @@ -2815,14 +2815,14 @@ impl fmt::Pointer for Unique { #[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a mut T> for Unique { fn from(reference: &'a mut T) -> Self { - Unique { pointer: NonZero(reference as _), _marker: PhantomData } + Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData } } } #[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a T> for Unique { fn from(reference: &'a T) -> Self { - Unique { pointer: NonZero(reference as _), _marker: PhantomData } + Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData } } } @@ -2895,7 +2895,7 @@ impl NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - NonNull { pointer: NonZero(ptr as _) } + NonNull { pointer: unsafe { NonZero(ptr as _) } } } /// Creates a new `NonNull` if `ptr` is non-null. @@ -2903,7 +2903,7 @@ impl NonNull { #[inline] pub fn new(ptr: *mut T) -> Option { if !ptr.is_null() { - Some(NonNull { pointer: NonZero(ptr as _) }) + Some(NonNull { pointer: unsafe { NonZero(ptr as _) } }) } else { None } @@ -3025,7 +3025,7 @@ impl From> for NonNull { impl<'a, T: ?Sized> From<&'a mut T> for NonNull { #[inline] fn from(reference: &'a mut T) -> Self { - NonNull { pointer: NonZero(reference as _) } + NonNull { pointer: unsafe { NonZero(reference as _) } } } } @@ -3033,6 +3033,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull { impl<'a, T: ?Sized> From<&'a T> for NonNull { #[inline] fn from(reference: &'a T) -> Self { - NonNull { pointer: NonZero(reference as _) } + NonNull { pointer: unsafe { NonZero(reference as _) } } } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 0547e4476cbe4..2c80e57374999 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -24,6 +24,8 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext}; use syntax::ast; use syntax::symbol::Symbol; +use std::ops::Bound; + use util; pub struct UnsafetyChecker<'a, 'tcx: 'a> { @@ -136,8 +138,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if let &Rvalue::Aggregate(box ref aggregate, _) = rvalue { match aggregate { &AggregateKind::Array(..) | - &AggregateKind::Tuple | - &AggregateKind::Adt(..) => {} + &AggregateKind::Tuple => {} + &AggregateKind::Adt(ref def, ..) => { + match self.tcx.layout_scalar_valid_range(def.did) { + (Bound::Unbounded, Bound::Unbounded) => {}, + _ => self.require_unsafe( + "initializing type with `rustc_layout_scalar_valid_range` attr", + "initializing `NonZero` with a `0` violates layout constraints \ + and is undefined behavior", + UnsafetyViolationKind::MinConstFn, + ), + } + } &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => { let UnsafetyCheckResult { diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs new file mode 100644 index 0000000000000..f559c23ff0f54 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -0,0 +1,47 @@ +// 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. + +#![unstable(feature = "humans", + reason = "who ever let humans program computers, + we're apparently really bad at it", + issue = "0")] + +#![feature(rustc_const_unstable, const_fn, foo, foo2)] +#![feature(min_const_unsafe_fn)] +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo")] +const unsafe fn foo() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn` + +#[unstable(feature = "rust1", issue="0")] +const unsafe fn foo2() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn` + +#[stable(feature = "rust1", since = "1.0.0")] +// conformity is required, even with `const_fn` feature gate +const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op + +// check whether this function cannot be called even with the feature gate active +#[unstable(feature = "foo2", issue="0")] +const unsafe fn foo2_gated() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr new file mode 100644 index 0000000000000..37be2889173f8 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -0,0 +1,26 @@ +error: can only call other `min_const_fn` within a `min_const_fn` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:41 + | +LL | const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn` + | ^^^^^ + +error: can only call other `min_const_fn` within a `min_const_fn` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:42 + | +LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn` + | ^^^^^^ + +error: only int, `bool` and `char` operations are stable in const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:37:33 + | +LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op + | ^^^^^^^^^^^^^ + +error: can only call other `min_const_fn` within a `min_const_fn` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:45:48 + | +LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs new file mode 100644 index 0000000000000..131bc97c85a2a --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -0,0 +1,43 @@ +// 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. + +#![unstable(feature = "humans", + reason = "who ever let humans program computers, + we're apparently really bad at it", + issue = "0")] + +#![feature(rustc_const_unstable, const_fn, foo, foo2)] +#![feature(min_const_unsafe_fn)] +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo")] +const fn foo() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn` + +#[unstable(feature = "rust1", issue="0")] +const fn foo2() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` + +// check whether this function cannot be called even with the feature gate active +#[unstable(feature = "foo2", issue="0")] +const fn foo2_gated() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr new file mode 100644 index 0000000000000..0b58dc1294be0 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -0,0 +1,20 @@ +error: can only call other `min_const_fn` within a `min_const_fn` + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:26:32 + | +LL | const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn` + | ^^^^^ + +error: can only call other `min_const_fn` within a `min_const_fn` + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:33 + | +LL | const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` + | ^^^^^^ + +error: can only call other `min_const_fn` within a `min_const_fn` + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:41:39 + | +LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` + | ^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From ec6573f33b15275551af321df1a19cfd3d835982 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 15:08:27 +0100 Subject: [PATCH 05/23] Make `newtype_index` safe --- src/librustc/dep_graph/graph.rs | 1 + src/librustc/dep_graph/serialized.rs | 1 + src/librustc/lib.rs | 1 + src/librustc/middle/region.rs | 1 + src/librustc/mir/mod.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/sty.rs | 2 +- src/librustc_data_structures/indexed_vec.rs | 24 +++++++++++++++---- src/librustc_mir/borrow_check/location.rs | 1 + .../borrow_check/nll/constraints/mod.rs | 1 + .../borrow_check/nll/region_infer/values.rs | 1 + .../nll/type_check/liveness/liveness_map.rs | 1 + .../nll/type_check/liveness/local_use_map.rs | 1 + src/librustc_mir/build/mod.rs | 1 + 14 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 4c94c993ab405..06287bda63a49 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -18,6 +18,7 @@ use std::env; use std::hash::Hash; use ty::{self, TyCtxt}; use util::common::{ProfileQueriesMsg, profq_msg}; +use serialize::{Decodable, Decoder}; use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs index 0c6c224fa914c..992ebd0efb15f 100644 --- a/src/librustc/dep_graph/serialized.rs +++ b/src/librustc/dep_graph/serialized.rs @@ -13,6 +13,7 @@ use dep_graph::DepNode; use ich::Fingerprint; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use serialize::{Decodable, Decoder}; newtype_index! { pub struct SerializedDepNodeIndex { .. } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ddb0c5bf22ab6..99412c02c43a6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -69,6 +69,7 @@ #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(transpose_result)] +#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))] #![recursion_limit="512"] diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 35d1a4dd2cb7c..1440d91b47e63 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -28,6 +28,7 @@ use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use ty::TyCtxt; use ty::query::Providers; +use serialize::{Decodable, Decoder}; use hir; use hir::Node; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c0581121efa1c..549e13bad642a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -25,7 +25,7 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::MappedReadGuard; -use rustc_serialize as serialize; +use rustc_serialize::{self as serialize, Decodable, Decoder}; use smallvec::SmallVec; use std::borrow::Cow; use std::fmt::{self, Debug, Formatter, Write}; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4633ab1166347..8ff93cee25022 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -41,7 +41,7 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use arena::SyncDroplessArena; use session::DataTypeKind; -use serialize::{self, Encodable, Encoder}; +use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::cmp::{self, Ordering}; use std::fmt; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 1416cb17feaed..fa45b8c776837 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -29,7 +29,7 @@ use rustc_target::spec::abi; use syntax::ast::{self, Ident}; use syntax::symbol::{keywords, InternedString}; -use serialize; +use serialize::{self, Decodable, Decoder}; use hir; diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index a59bf9d530c4d..c35490ce35b4f 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -98,12 +98,18 @@ macro_rules! newtype_index { @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt]) => ( - #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)] + #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)] #[rustc_layout_scalar_valid_range_end($max)] $v struct $type { private: u32 } + impl Clone for $type { + fn clone(&self) -> Self { + *self + } + } + impl $type { $v const MAX_AS_U32: u32 = $max; @@ -145,7 +151,7 @@ macro_rules! newtype_index { #[inline] $v const unsafe fn from_u32_unchecked(value: u32) -> Self { - $type { private: value } + unsafe { $type { private: value } } } /// Extract value of this index as an integer. @@ -328,12 +334,17 @@ macro_rules! newtype_index { derive [$($derives:ident,)+] $($tokens:tt)*) => ( newtype_index!( - @derives [$($derives,)+ RustcDecodable, RustcEncodable,] + @derives [$($derives,)+ RustcEncodable,] @type [$type] @max [$max] @vis [$v] @debug_format [$debug_format] $($tokens)*); + impl Decodable for $type { + fn decode(d: &mut D) -> Result { + d.read_u32().into() + } + } ); // The case where no derives are added, but encodable is overridden. Don't @@ -360,12 +371,17 @@ macro_rules! newtype_index { @debug_format [$debug_format:tt] $($tokens:tt)*) => ( newtype_index!( - @derives [RustcDecodable, RustcEncodable,] + @derives [RustcEncodable,] @type [$type] @max [$max] @vis [$v] @debug_format [$debug_format] $($tokens)*); + impl Decodable for $type { + fn decode(d: &mut D) -> Result { + d.read_u32().map(Self::from) + } + } ); // Rewrite final without comma to one that includes comma diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs index b3e159dd84457..2d593d851138b 100644 --- a/src/librustc_mir/borrow_check/location.rs +++ b/src/librustc_mir/borrow_check/location.rs @@ -10,6 +10,7 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_serialize::{Decodable, Decoder}; /// Maps between a MIR Location, which identifies a particular /// statement within a basic block, to a "rich location", which diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index a873af8333a7f..37b11a77184d4 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -13,6 +13,7 @@ use rustc::ty::RegionVid; use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use borrow_check::nll::type_check::Locations; +use rustc_serialize::{Decodable, Decoder}; use std::fmt; use std::ops::Deref; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 69e2c896d33e5..5ce80ca236dbb 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -16,6 +16,7 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt::Debug; use std::rc::Rc; +use rustc_serialize::{Decodable, Decoder}; /// Maps between a `Location` and a `PointIndex` (and vice versa). crate struct RegionValueElements { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs index cc176cbc40392..d1a1d2aea248a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs @@ -23,6 +23,7 @@ use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use util::liveness::LiveVariableMap; +use rustc_serialize::{Decodable, Decoder}; /// Map between Local and LiveVar indices: the purpose of this /// map is to define the subset of local variables for which we need diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index 4b39d58cd96a8..9e0eaf61e94a4 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -15,6 +15,7 @@ use rustc::mir::{Local, Location, Mir}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::vec_linked_list as vll; use util::liveness::{categorize, DefUse, LiveVariableMap}; +use rustc_serialize::{Decodable, Decoder}; /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index cc927df6350bd..1a5a089c7aa03 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -32,6 +32,7 @@ use syntax::ast; use syntax::attr::{self, UnwindAttr}; use syntax::symbol::keywords; use syntax_pos::Span; +use rustc_serialize::{Decodable, Decoder}; use transform::MirSource; use util as mir_util; From 693c55372e950bcf19a95d713a82250a5f4d1bba Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 15:21:44 +0100 Subject: [PATCH 06/23] Move ref to packed struct field check into projection arm --- src/librustc_mir/transform/check_unsafety.rs | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 2c80e57374999..1e90f5a9584b2 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -166,28 +166,28 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { place: &Place<'tcx>, context: PlaceContext<'tcx>, location: Location) { - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.mir, self.param_env, place) { - let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; - self.register_violations(&[UnsafetyViolation { - source_info, - description: Symbol::intern("borrow of packed field").as_interned_str(), - details: - Symbol::intern("fields of packed structs might be misaligned: \ - dereferencing a misaligned pointer or even just creating a \ - misaligned reference is undefined behavior") - .as_interned_str(), - kind: UnsafetyViolationKind::BorrowPacked(lint_root) - }], &[]); - } - } - match place { &Place::Projection(box Projection { ref base, ref elem }) => { + if context.is_borrow() { + if util::is_disaligned(self.tcx, self.mir, self.param_env, place) { + let source_info = self.source_info; + let lint_root = + self.source_scope_local_data[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: Symbol::intern("borrow of packed field").as_interned_str(), + details: + Symbol::intern("fields of packed structs might be misaligned: \ + dereferencing a misaligned pointer or even just \ + creating a misaligned reference is undefined \ + behavior") + .as_interned_str(), + kind: UnsafetyViolationKind::BorrowPacked(lint_root) + }], &[]); + } + } let old_source_info = self.source_info; if let &Place::Local(local) = base { if self.mir.local_decls[local].internal { From 8bdb11c4d94a05c3d6148e52b53a6b95ec9f0a13 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 16:30:05 +0100 Subject: [PATCH 07/23] Forbid the creation of mutable borrows to fields of layout constrained types --- src/librustc_mir/transform/check_unsafety.rs | 40 ++++++++++++++++++++ src/test/ui/unsafe/ranged_ints.rs | 8 ++++ src/test/ui/unsafe/ranged_ints.stderr | 11 ++++++ src/test/ui/unsafe/ranged_ints2.rs | 9 +++++ src/test/ui/unsafe/ranged_ints2.stderr | 11 ++++++ 5 files changed, 79 insertions(+) create mode 100644 src/test/ui/unsafe/ranged_ints.rs create mode 100644 src/test/ui/unsafe/ranged_ints.stderr create mode 100644 src/test/ui/unsafe/ranged_ints2.rs create mode 100644 src/test/ui/unsafe/ranged_ints2.stderr diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 1e90f5a9584b2..05052c8a8c8c9 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -187,6 +187,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } + if context.is_mutating_use() { + self.check_mut_borrowing_layout_constrained_field(place); + } } let old_source_info = self.source_info; if let &Place::Local(local) = base { @@ -350,6 +353,43 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { (node_id, is_used && !within_unsafe) })); } + fn check_mut_borrowing_layout_constrained_field( + &mut self, + mut place: &Place<'tcx>, + ) { + while let &Place::Projection(box Projection { + ref base, ref elem + }) = place { + match *elem { + ProjectionElem::Field(..) => { + let ty = base.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); + match ty.sty { + ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { + (Bound::Unbounded, Bound::Unbounded) => {}, + _ => { + let source_info = self.source_info; + self.register_violations(&[UnsafetyViolation { + source_info, + description: Symbol::intern( + "borrow of layout constrained field", + ).as_interned_str(), + details: + Symbol::intern( + "references to fields of layout constrained fields \ + lose the constraints", + ).as_interned_str(), + kind: UnsafetyViolationKind::MinConstFn, + }], &[]); + } + }, + _ => {} + } + } + _ => {} + } + place = base; + } + } } pub(crate) fn provide(providers: &mut Providers) { diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs new file mode 100644 index 0000000000000..c9fdadeaf05fd --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints.rs @@ -0,0 +1,8 @@ +#![feature(rustc_attrs)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() { + let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr +} \ No newline at end of file diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.stderr new file mode 100644 index 0000000000000..c28adba9ee536 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints.stderr @@ -0,0 +1,11 @@ +error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + --> $DIR/ranged_ints.rs:7:14 + | +LL | let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr + | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr + | + = note: initializing `NonZero` with a `0` violates layout constraints and is undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints2.rs b/src/test/ui/unsafe/ranged_ints2.rs new file mode 100644 index 0000000000000..9e1acb1a7b1a3 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints2.rs @@ -0,0 +1,9 @@ +#![feature(rustc_attrs)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() { + let mut x = unsafe { NonZero(1) }; + let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe +} \ No newline at end of file diff --git a/src/test/ui/unsafe/ranged_ints2.stderr b/src/test/ui/unsafe/ranged_ints2.stderr new file mode 100644 index 0000000000000..77313f27a420b --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints2.stderr @@ -0,0 +1,11 @@ +error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block + --> $DIR/ranged_ints2.rs:8:13 + | +LL | let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe + | ^^^^^^^^ borrow of layout constrained field + | + = note: references to fields of layout constrained fields lose the constraints + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. From 14218e39698156b3c0c9b64b5cc17ee4c9ed17e0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 23:39:29 +0100 Subject: [PATCH 08/23] Trailing newlines again --- src/test/ui/unsafe/ranged_ints.rs | 2 +- src/test/ui/unsafe/ranged_ints2.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs index c9fdadeaf05fd..0fa2da917e9f8 100644 --- a/src/test/ui/unsafe/ranged_ints.rs +++ b/src/test/ui/unsafe/ranged_ints.rs @@ -5,4 +5,4 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr -} \ No newline at end of file +} diff --git a/src/test/ui/unsafe/ranged_ints2.rs b/src/test/ui/unsafe/ranged_ints2.rs index 9e1acb1a7b1a3..3738b7f5af4a7 100644 --- a/src/test/ui/unsafe/ranged_ints2.rs +++ b/src/test/ui/unsafe/ranged_ints2.rs @@ -6,4 +6,4 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { let mut x = unsafe { NonZero(1) }; let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe -} \ No newline at end of file +} From c4a850078cbcc8cd3d79483b51767f1171d81f88 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 4 Nov 2018 12:22:58 +0100 Subject: [PATCH 09/23] Adjust a rustc test to the safety changes --- src/test/run-pass-fulldeps/newtype_index.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs index 3cd622a33b173..4c5a21201d674 100644 --- a/src/test/run-pass-fulldeps/newtype_index.rs +++ b/src/test/run-pass-fulldeps/newtype_index.rs @@ -1,7 +1,8 @@ -#![feature(rustc_attrs, rustc_private, step_trait)] +#![feature(rustc_attrs, rustc_private, step_trait, min_const_unsafe_fn)] #[macro_use] extern crate rustc_data_structures; extern crate rustc_serialize; +use rustc_serialize::{Decodable, Decoder}; use rustc_data_structures::indexed_vec::Idx; From 081c49783f5cfc24f66f3ac36244d816567cc120 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 4 Nov 2018 12:48:51 +0100 Subject: [PATCH 10/23] generalize the message about the creation of layout restricted types --- src/librustc_mir/transform/check_unsafety.rs | 4 ++-- src/test/ui/unsafe/ranged_ints.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 05052c8a8c8c9..2a80f27ecab5a 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -144,8 +144,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { (Bound::Unbounded, Bound::Unbounded) => {}, _ => self.require_unsafe( "initializing type with `rustc_layout_scalar_valid_range` attr", - "initializing `NonZero` with a `0` violates layout constraints \ - and is undefined behavior", + "initializing a layout restricted type's field with a value outside \ + the valid range is undefined behavior", UnsafetyViolationKind::MinConstFn, ), } diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.stderr index c28adba9ee536..f59a930b5a901 100644 --- a/src/test/ui/unsafe/ranged_ints.stderr +++ b/src/test/ui/unsafe/ranged_ints.stderr @@ -4,7 +4,7 @@ error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is u LL | let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr | - = note: initializing `NonZero` with a `0` violates layout constraints and is undefined behavior + = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior error: aborting due to previous error From 1894a5fe2c72a1e22897026f34e5f9035cc169ff Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 4 Nov 2018 13:45:26 +0100 Subject: [PATCH 11/23] Also make immutable references to non-freeze restricted value range types unsafe --- src/libcore/marker.rs | 2 +- src/libcore/nonzero.rs | 9 +++++---- src/librustc_mir/transform/check_unsafety.rs | 6 +++++- src/test/ui/unsafe/ranged_ints3.rs | 11 +++++++++++ src/test/ui/unsafe/ranged_ints3.stderr | 11 +++++++++++ 5 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/unsafe/ranged_ints3.rs create mode 100644 src/test/ui/unsafe/ranged_ints3.stderr diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3bcdfabbb245e..23f07773f3f34 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -596,7 +596,7 @@ mod impls { /// This affects, for example, whether a `static` of that type is /// placed in read-only static memory or writable static memory. #[lang = "freeze"] -unsafe auto trait Freeze {} +pub(crate) unsafe auto trait Freeze {} impl !Freeze for UnsafeCell {} unsafe impl Freeze for PhantomData {} diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 22d93a5301efa..a89c6ca60cbea 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -11,22 +11,23 @@ //! Exposes the NonZero lang item which provides optimization hints. use ops::{CoerceUnsized, DispatchFromDyn}; +use marker::Freeze; /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. #[rustc_layout_scalar_valid_range_start(1)] #[derive(Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] -pub(crate) struct NonZero(pub(crate) T); +pub(crate) struct NonZero(pub(crate) T); // Do not call `T::clone` as theoretically it could turn the field into `0` // invalidating `NonZero`'s invariant. -impl Clone for NonZero { +impl Clone for NonZero { fn clone(&self) -> Self { unsafe { NonZero(self.0) } } } -impl, U> CoerceUnsized> for NonZero {} +impl + Freeze, U: Freeze> CoerceUnsized> for NonZero {} -impl, U> DispatchFromDyn> for NonZero {} +impl + Freeze, U: Freeze> DispatchFromDyn> for NonZero {} diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 2a80f27ecab5a..c7a785ad2c520 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -187,7 +187,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } - if context.is_mutating_use() { + let is_freeze = base + .ty(self.mir, self.tcx) + .to_ty(self.tcx) + .is_freeze(self.tcx, self.param_env, self.source_info.span); + if context.is_mutating_use() || !is_freeze { self.check_mut_borrowing_layout_constrained_field(place); } } diff --git a/src/test/ui/unsafe/ranged_ints3.rs b/src/test/ui/unsafe/ranged_ints3.rs new file mode 100644 index 0000000000000..d68c712227af2 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints3.rs @@ -0,0 +1,11 @@ +#![feature(rustc_attrs)] + +use std::cell::Cell; + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() { + let mut x = unsafe { NonZero(Cell::new(1)) }; + let y = &x.0; //~ ERROR borrow of layout constrained field is unsafe +} diff --git a/src/test/ui/unsafe/ranged_ints3.stderr b/src/test/ui/unsafe/ranged_ints3.stderr new file mode 100644 index 0000000000000..b5aa9089b5f62 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints3.stderr @@ -0,0 +1,11 @@ +error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block + --> $DIR/ranged_ints3.rs:10:13 + | +LL | let y = &x.0; //~ ERROR borrow of layout constrained field is unsafe + | ^^^^ borrow of layout constrained field + | + = note: references to fields of layout constrained fields lose the constraints + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. From 55abc0bc907b84b0fe7a9a4793c1549dad978762 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 5 Nov 2018 13:26:07 +0100 Subject: [PATCH 12/23] Also prevent mutation fields directly --- src/librustc_mir/transform/check_unsafety.rs | 42 +++++++++++++------- src/test/ui/unsafe/ranged_ints2.rs | 2 +- src/test/ui/unsafe/ranged_ints2.stderr | 8 ++-- src/test/ui/unsafe/ranged_ints3.rs | 2 +- src/test/ui/unsafe/ranged_ints3.stderr | 8 ++-- src/test/ui/unsafe/ranged_ints4.rs | 9 +++++ src/test/ui/unsafe/ranged_ints4.stderr | 11 +++++ 7 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 src/test/ui/unsafe/ranged_ints4.rs create mode 100644 src/test/ui/unsafe/ranged_ints4.stderr diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index c7a785ad2c520..b124f8b1c0be9 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -187,13 +187,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } - let is_freeze = base - .ty(self.mir, self.tcx) - .to_ty(self.tcx) - .is_freeze(self.tcx, self.param_env, self.source_info.span); - if context.is_mutating_use() || !is_freeze { - self.check_mut_borrowing_layout_constrained_field(place); - } + } + let is_borrow_of_interior_mut = context.is_borrow() && !base + .ty(self.mir, self.tcx) + .to_ty(self.tcx) + .is_freeze(self.tcx, self.param_env, self.source_info.span); + if context.is_mutating_use() || is_borrow_of_interior_mut { + self.check_mut_borrowing_layout_constrained_field( + place, context.is_mutating_use(), + ); } let old_source_info = self.source_info; if let &Place::Local(local) = base { @@ -360,6 +362,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn check_mut_borrowing_layout_constrained_field( &mut self, mut place: &Place<'tcx>, + is_mut_use: bool, ) { while let &Place::Projection(box Projection { ref base, ref elem @@ -371,17 +374,26 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, _ => { + let (description, details) = if is_mut_use { + ( + "mutation of layout constrained field", + "mutating layout constrained fields cannot statically be \ + checked for valid values", + ) + } else { + ( + "borrow of layout constrained field with interior \ + mutability", + "references to fields of layout constrained fields \ + lose the constraints. Coupled with interior mutability, \ + the field can be changed to invalid values", + ) + }; let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern( - "borrow of layout constrained field", - ).as_interned_str(), - details: - Symbol::intern( - "references to fields of layout constrained fields \ - lose the constraints", - ).as_interned_str(), + description: Symbol::intern(description).as_interned_str(), + details: Symbol::intern(details).as_interned_str(), kind: UnsafetyViolationKind::MinConstFn, }], &[]); } diff --git a/src/test/ui/unsafe/ranged_ints2.rs b/src/test/ui/unsafe/ranged_ints2.rs index 3738b7f5af4a7..68ba120b279c0 100644 --- a/src/test/ui/unsafe/ranged_ints2.rs +++ b/src/test/ui/unsafe/ranged_ints2.rs @@ -5,5 +5,5 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { let mut x = unsafe { NonZero(1) }; - let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe + let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe } diff --git a/src/test/ui/unsafe/ranged_ints2.stderr b/src/test/ui/unsafe/ranged_ints2.stderr index 77313f27a420b..ae63f47ed74a7 100644 --- a/src/test/ui/unsafe/ranged_ints2.stderr +++ b/src/test/ui/unsafe/ranged_ints2.stderr @@ -1,10 +1,10 @@ -error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block +error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2.rs:8:13 | -LL | let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe - | ^^^^^^^^ borrow of layout constrained field +LL | let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe + | ^^^^^^^^ mutation of layout constrained field | - = note: references to fields of layout constrained fields lose the constraints + = note: mutating layout constrained fields cannot statically be checked for valid values error: aborting due to previous error diff --git a/src/test/ui/unsafe/ranged_ints3.rs b/src/test/ui/unsafe/ranged_ints3.rs index d68c712227af2..47d67fac6785c 100644 --- a/src/test/ui/unsafe/ranged_ints3.rs +++ b/src/test/ui/unsafe/ranged_ints3.rs @@ -7,5 +7,5 @@ use std::cell::Cell; pub(crate) struct NonZero(pub(crate) T); fn main() { let mut x = unsafe { NonZero(Cell::new(1)) }; - let y = &x.0; //~ ERROR borrow of layout constrained field is unsafe + let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability } diff --git a/src/test/ui/unsafe/ranged_ints3.stderr b/src/test/ui/unsafe/ranged_ints3.stderr index b5aa9089b5f62..311a058fdb07f 100644 --- a/src/test/ui/unsafe/ranged_ints3.stderr +++ b/src/test/ui/unsafe/ranged_ints3.stderr @@ -1,10 +1,10 @@ -error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block +error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block --> $DIR/ranged_ints3.rs:10:13 | -LL | let y = &x.0; //~ ERROR borrow of layout constrained field is unsafe - | ^^^^ borrow of layout constrained field +LL | let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability + | ^^^^ borrow of layout constrained field with interior mutability | - = note: references to fields of layout constrained fields lose the constraints + = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values error: aborting due to previous error diff --git a/src/test/ui/unsafe/ranged_ints4.rs b/src/test/ui/unsafe/ranged_ints4.rs new file mode 100644 index 0000000000000..d8632c48434f2 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints4.rs @@ -0,0 +1,9 @@ +#![feature(rustc_attrs)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() { + let mut x = unsafe { NonZero(1) }; + x.0 = 0; //~ ERROR mutation of layout constrained field is unsafe +} diff --git a/src/test/ui/unsafe/ranged_ints4.stderr b/src/test/ui/unsafe/ranged_ints4.stderr new file mode 100644 index 0000000000000..c6468b643b41a --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints4.stderr @@ -0,0 +1,11 @@ +error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block + --> $DIR/ranged_ints4.rs:8:5 + | +LL | x.0 = 0; //~ ERROR mutation of layout constrained field is unsafe + | ^^^^^^^ mutation of layout constrained field + | + = note: mutating layout constrained fields cannot statically be checked for valid values + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. From e5d90652e203aee41ae41b7ad696652e77654766 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 5 Nov 2018 13:29:17 +0100 Subject: [PATCH 13/23] Comment on the unsafety code for layout constrained fields --- src/librustc_mir/transform/check_unsafety.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index b124f8b1c0be9..671ca355dbfc1 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -192,6 +192,12 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { .ty(self.mir, self.tcx) .to_ty(self.tcx) .is_freeze(self.tcx, self.param_env, self.source_info.span); + // prevent + // * `&mut x.field` + // * `x.field = y;` + // * `&x.field` if `field`'s type has interior mutability + // because either of these would allow modifying the layout constrained field and + // insert values that violate the layout constraints. if context.is_mutating_use() || is_borrow_of_interior_mut { self.check_mut_borrowing_layout_constrained_field( place, context.is_mutating_use(), From 4497ff37627d860690613249a31cf3ee4c4195ef Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 5 Nov 2018 18:06:26 +0100 Subject: [PATCH 14/23] Emit feature gate suggestion --- src/librustc/ich/impls_mir.rs | 3 +- src/librustc/mir/mod.rs | 8 +- src/librustc_mir/transform/check_unsafety.rs | 74 +++++++++++++------ .../min_const_fn/min_const_fn_unsafe.rs | 6 +- .../min_const_fn/min_const_fn_unsafe.stderr | 24 +++--- 5 files changed, 75 insertions(+), 40 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index d98bb82aabad1..3b9c8ae2d3c50 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -46,7 +46,8 @@ impl_stable_hash_for!(enum mir::BorrowKind { impl_stable_hash_for!(enum mir::UnsafetyViolationKind { General, - MinConstFn, + GeneralAndConstFn, + GatedConstFnCall, ExternStatic(lint_node_id), BorrowPacked(lint_node_id), }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 549e13bad642a..09b344cd38d25 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2770,9 +2770,11 @@ impl Location { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UnsafetyViolationKind { General, - /// Right now function calls to `const unsafe fn` are the only permitted unsafe operation in - /// const fn. Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations - MinConstFn, + /// Right now function calls to `const unsafe fn` are only permitted behind a feature gate + /// Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations. + GatedConstFnCall, + /// Permitted in const fn and regular fns + GeneralAndConstFn, ExternStatic(ast::NodeId), BorrowPacked(ast::NodeId), } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 671ca355dbfc1..25dbd160d19f4 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -23,6 +23,7 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext}; use syntax::ast; use syntax::symbol::Symbol; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use std::ops::Bound; @@ -96,7 +97,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if let hir::Unsafety::Unsafe = sig.unsafety() { self.require_unsafe("call to unsafe function", "consult the function's documentation for information on how to avoid \ - undefined behavior", UnsafetyViolationKind::MinConstFn) + undefined behavior", UnsafetyViolationKind::GatedConstFnCall) } } } @@ -146,7 +147,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { "initializing type with `rustc_layout_scalar_valid_range` attr", "initializing a layout restricted type's field with a value outside \ the valid range is undefined behavior", - UnsafetyViolationKind::MinConstFn, + UnsafetyViolationKind::GeneralAndConstFn, ), } } @@ -319,12 +320,21 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { (Safety::Safe, _) => { for violation in violations { let mut violation = violation.clone(); - if self.min_const_fn { - // overwrite unsafety violation in const fn with a single hard error kind - violation.kind = UnsafetyViolationKind::MinConstFn; - } else if let UnsafetyViolationKind::MinConstFn = violation.kind { - // outside of const fns we treat `MinConstFn` and `General` the same - violation.kind = UnsafetyViolationKind::General; + match violation.kind { + UnsafetyViolationKind::GeneralAndConstFn | + UnsafetyViolationKind::General => {}, + UnsafetyViolationKind::BorrowPacked(_) | + UnsafetyViolationKind::ExternStatic(_) => if self.min_const_fn { + // const fns don't need to be backwards compatible and can + // emit these violations as a hard error instead of a backwards + // compat lint + violation.kind = UnsafetyViolationKind::General; + }, + UnsafetyViolationKind::GatedConstFnCall => { + // safe code can't call unsafe const fns, this `UnsafetyViolationKind` + // is only relevant for `Safety::ExplicitUnsafe` in `unsafe const fn`s + violation.kind = UnsafetyViolationKind::General; + } } if !self.violations.contains(&violation) { self.violations.push(violation) @@ -344,13 +354,24 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { for violation in violations { match violation.kind { // these are allowed - UnsafetyViolationKind::MinConstFn + UnsafetyViolationKind::GatedConstFnCall => { // if `#![feature(min_const_unsafe_fn)]` is active - if self.tcx.sess.features_untracked().min_const_unsafe_fn => {}, - _ => { + if !self.tcx.sess.features_untracked().min_const_unsafe_fn { + if !self.violations.contains(&violation) { + self.violations.push(violation.clone()) + } + } + } + // these unsafe things are stable in const fn + UnsafetyViolationKind::GeneralAndConstFn => {}, + UnsafetyViolationKind::General | + UnsafetyViolationKind::BorrowPacked(_) | + UnsafetyViolationKind::ExternStatic(_) => { let mut violation = violation.clone(); - // overwrite unsafety violation in const fn with a hard error - violation.kind = UnsafetyViolationKind::MinConstFn; + // const fns don't need to be backwards compatible and can + // emit these violations as a hard error instead of a backwards + // compat lint + violation.kind = UnsafetyViolationKind::General; if !self.violations.contains(&violation) { self.violations.push(violation) } @@ -400,7 +421,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { source_info, description: Symbol::intern(description).as_interned_str(), details: Symbol::intern(details).as_interned_str(), - kind: UnsafetyViolationKind::MinConstFn, + kind: UnsafetyViolationKind::GeneralAndConstFn, }], &[]); } }, @@ -592,6 +613,16 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { } in violations.iter() { // Report an error. match kind { + UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => { + tcx.sess.struct_span_err( + source_info.span, + &format!("{} is unsafe and unsafe operations \ + are not allowed in const fn", description)) + .span_label(source_info.span, &description.as_str()[..]) + .note(&details.as_str()[..]) + .emit(); + } + UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { struct_span_err!( tcx.sess, source_info.span, E0133, @@ -600,14 +631,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { .note(&details.as_str()[..]) .emit(); } - UnsafetyViolationKind::MinConstFn => { - tcx.sess.struct_span_err( + UnsafetyViolationKind::GatedConstFnCall => { + emit_feature_err( + &tcx.sess.parse_sess, + "min_const_unsafe_fn", source_info.span, - &format!("{} is unsafe and unsafe operations \ - are not allowed in const fn", description)) - .span_label(source_info.span, &description.as_str()[..]) - .note(&details.as_str()[..]) - .emit(); + GateIssue::Language, + "calls to `const unsafe fn` in const fns are unstable", + ); + } UnsafetyViolationKind::ExternStatic(lint_node_id) => { tcx.lint_node_note(SAFE_EXTERN_STATICS, diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index 7a84992e14b36..02a357551df30 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -18,13 +18,13 @@ const fn no_unsafe() { unsafe {} } // not ok const fn foo8() -> i32 { - unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn + unsafe { foo4() } //~ ERROR calls to `const unsafe fn` in const fns are unstable } const fn foo9() -> *const String { - unsafe { foo5::() } //~ ERROR unsafe operations are not allowed in const fn + unsafe { foo5::() } //~ ERROR calls to `const unsafe fn` in const fns are unstable } const fn foo10() -> *const Vec> { - unsafe { foo6::>>() } //~ ERROR not allowed in const fn + unsafe { foo6::>>() } //~ ERROR calls to `const unsafe fn` in const fns } const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn //~^ dereferencing raw pointers in constant functions diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 17cba8569c148..0b8ff4717c128 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -14,29 +14,29 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn | = help: add #![feature(const_fn_union)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn +error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:21:14 | -LL | unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn - | ^^^^^^ call to unsafe function +LL | unsafe { foo4() } //~ ERROR calls to `const unsafe fn` in const fns are unstable + | ^^^^^^ | - = note: consult the function's documentation for information on how to avoid undefined behavior + = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn +error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:24:14 | -LL | unsafe { foo5::() } //~ ERROR unsafe operations are not allowed in const fn - | ^^^^^^^^^^^^^^^^ call to unsafe function +LL | unsafe { foo5::() } //~ ERROR calls to `const unsafe fn` in const fns are unstable + | ^^^^^^^^^^^^^^^^ | - = note: consult the function's documentation for information on how to avoid undefined behavior + = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn +error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:27:14 | -LL | unsafe { foo6::>>() } //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function +LL | unsafe { foo6::>>() } //~ ERROR calls to `const unsafe fn` in const fns + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consult the function's documentation for information on how to avoid undefined behavior + = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe.rs:29:51 From 37ef5e43af477d0cb04f70e9d868361b40cd7a08 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 6 Nov 2018 17:43:32 +0100 Subject: [PATCH 15/23] Add tests for stable unsafe features in const fn --- src/libcore/lib.rs | 1 - src/librustc/hir/mod.rs | 1 + src/librustc/lib.rs | 1 - src/librustc_target/abi/mod.rs | 1 + src/test/ui/unsafe/ranged_ints2_const.rs | 20 ++++++++++++++ src/test/ui/unsafe/ranged_ints2_const.stderr | 24 +++++++++++++++++ src/test/ui/unsafe/ranged_ints3_const.rs | 21 +++++++++++++++ src/test/ui/unsafe/ranged_ints3_const.stderr | 24 +++++++++++++++++ src/test/ui/unsafe/ranged_ints4_const.rs | 19 +++++++++++++ src/test/ui/unsafe/ranged_ints4_const.stderr | 28 ++++++++++++++++++++ src/test/ui/unsafe/ranged_ints_const.rs | 11 ++++++++ src/test/ui/unsafe/ranged_ints_const.stderr | 11 ++++++++ 12 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/unsafe/ranged_ints2_const.rs create mode 100644 src/test/ui/unsafe/ranged_ints2_const.stderr create mode 100644 src/test/ui/unsafe/ranged_ints3_const.rs create mode 100644 src/test/ui/unsafe/ranged_ints3_const.stderr create mode 100644 src/test/ui/unsafe/ranged_ints4_const.rs create mode 100644 src/test/ui/unsafe/ranged_ints4_const.stderr create mode 100644 src/test/ui/unsafe/ranged_ints_const.rs create mode 100644 src/test/ui/unsafe/ranged_ints_const.stderr diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d070160609d29..726e891df0ccf 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -93,7 +93,6 @@ #![feature(never_type)] #![feature(nll)] #![feature(exhaustive_patterns)] -#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 1674320165e65..597a773821703 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -122,6 +122,7 @@ impl serialize::UseSpecializedDecodable for HirId { // hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module mod item_local_id_inner { use rustc_data_structures::indexed_vec::Idx; + use serialize::{Decodable, Decoder}; /// An `ItemLocalId` uniquely identifies something within a given "item-like", /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no /// guarantee that the numerical value of a given `ItemLocalId` corresponds to diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 99412c02c43a6..ddb0c5bf22ab6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -69,7 +69,6 @@ #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(transpose_result)] -#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))] #![recursion_limit="512"] diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 50ce0ad6915da..27a4292543ad6 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -17,6 +17,7 @@ use std::fmt; use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_serialize::{Decodable, Decoder}; pub mod call; diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs new file mode 100644 index 0000000000000..a61e3329bdce8 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints2_const.rs @@ -0,0 +1,20 @@ +#![feature(rustc_attrs, const_let, const_fn)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() { +} + +const fn foo() -> NonZero { + let mut x = unsafe { NonZero(1) }; + let y = &mut x.0; //~ ERROR references in constant functions may only refer to immutable + //~^ ERROR mutation of layout constrained field is unsafe + unsafe { NonZero(1) } +} + +const fn bar() -> NonZero { + let mut x = unsafe { NonZero(1) }; + let y = unsafe { &mut x.0 }; //~ ERROR references in constant functions may only refer to immut + unsafe { NonZero(1) } +} diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr new file mode 100644 index 0000000000000..f79792ffba9be --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints2_const.stderr @@ -0,0 +1,24 @@ +error[E0017]: references in constant functions may only refer to immutable values + --> $DIR/ranged_ints2_const.rs:11:13 + | +LL | let y = &mut x.0; //~ ERROR references in constant functions may only refer to immutable + | ^^^^^^^^ constant functions require immutable values + +error[E0017]: references in constant functions may only refer to immutable values + --> $DIR/ranged_ints2_const.rs:18:22 + | +LL | let y = unsafe { &mut x.0 }; //~ ERROR references in constant functions may only refer to immut + | ^^^^^^^^ constant functions require immutable values + +error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block + --> $DIR/ranged_ints2_const.rs:11:13 + | +LL | let y = &mut x.0; //~ ERROR references in constant functions may only refer to immutable + | ^^^^^^^^ mutation of layout constrained field + | + = note: mutating layout constrained fields cannot statically be checked for valid values + +error: aborting due to 3 previous errors + +Some errors occurred: E0017, E0133. +For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/unsafe/ranged_ints3_const.rs b/src/test/ui/unsafe/ranged_ints3_const.rs new file mode 100644 index 0000000000000..6497b611224b6 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints3_const.rs @@ -0,0 +1,21 @@ +#![feature(rustc_attrs, const_let, const_fn)] + +use std::cell::Cell; + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() {} + +const fn foo() -> NonZero> { + let mut x = unsafe { NonZero(Cell::new(1)) }; + let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability + //~^ ERROR borrow of layout constrained field with interior mutability + unsafe { NonZero(Cell::new(1)) } +} + +const fn bar() -> NonZero> { + let mut x = unsafe { NonZero(Cell::new(1)) }; + let y = unsafe { &x.0 }; //~ ERROR cannot borrow a constant which may contain interior mut + unsafe { NonZero(Cell::new(1)) } +} diff --git a/src/test/ui/unsafe/ranged_ints3_const.stderr b/src/test/ui/unsafe/ranged_ints3_const.stderr new file mode 100644 index 0000000000000..d83d75787d948 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints3_const.stderr @@ -0,0 +1,24 @@ +error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead + --> $DIR/ranged_ints3_const.rs:12:13 + | +LL | let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability + | ^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead + --> $DIR/ranged_ints3_const.rs:19:22 + | +LL | let y = unsafe { &x.0 }; //~ ERROR cannot borrow a constant which may contain interior mut + | ^^^^ + +error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block + --> $DIR/ranged_ints3_const.rs:12:13 + | +LL | let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability + | ^^^^ borrow of layout constrained field with interior mutability + | + = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + +error: aborting due to 3 previous errors + +Some errors occurred: E0133, E0492. +For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints4_const.rs b/src/test/ui/unsafe/ranged_ints4_const.rs new file mode 100644 index 0000000000000..09689579639e7 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints4_const.rs @@ -0,0 +1,19 @@ +#![feature(rustc_attrs, const_let, const_fn)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() {} + +const fn foo() -> NonZero { + let mut x = unsafe { NonZero(1) }; + x.0 = 0; //~ ERROR statements in constant functions are unstable + //~^ ERROR mutation of layout constrained field is unsafe + x +} + +const fn bar() -> NonZero { + let mut x = unsafe { NonZero(1) }; + unsafe { x.0 = 0 }; //~ ERROR statements in constant functions are unstable + x +} diff --git a/src/test/ui/unsafe/ranged_ints4_const.stderr b/src/test/ui/unsafe/ranged_ints4_const.stderr new file mode 100644 index 0000000000000..284ba3603af2e --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints4_const.stderr @@ -0,0 +1,28 @@ +error[E0658]: statements in constant functions are unstable (see issue #48821) + --> $DIR/ranged_ints4_const.rs:10:5 + | +LL | x.0 = 0; //~ ERROR statements in constant functions are unstable + | ^^^^^^^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: statements in constant functions are unstable (see issue #48821) + --> $DIR/ranged_ints4_const.rs:17:14 + | +LL | unsafe { x.0 = 0 }; //~ ERROR statements in constant functions are unstable + | ^^^^^^^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block + --> $DIR/ranged_ints4_const.rs:10:5 + | +LL | x.0 = 0; //~ ERROR statements in constant functions are unstable + | ^^^^^^^ mutation of layout constrained field + | + = note: mutating layout constrained fields cannot statically be checked for valid values + +error: aborting due to 3 previous errors + +Some errors occurred: E0133, E0658. +For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints_const.rs b/src/test/ui/unsafe/ranged_ints_const.rs new file mode 100644 index 0000000000000..8477772867e91 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints_const.rs @@ -0,0 +1,11 @@ +#![feature(rustc_attrs)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() {} + +const fn foo() -> NonZero { NonZero(0) } +//~^ ERROR initializing type with `rustc_layout_scalar_valid_range` attr is unsafe + +const fn bar() -> NonZero { unsafe { NonZero(0) } } diff --git a/src/test/ui/unsafe/ranged_ints_const.stderr b/src/test/ui/unsafe/ranged_ints_const.stderr new file mode 100644 index 0000000000000..584ad40a92bb0 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints_const.stderr @@ -0,0 +1,11 @@ +error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + --> $DIR/ranged_ints_const.rs:8:34 + | +LL | const fn foo() -> NonZero { NonZero(0) } + | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr + | + = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. From 3ce211dbd0f55f79212fcde773a2060ccfec031d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 19 Nov 2018 14:45:40 +0100 Subject: [PATCH 16/23] Increase code-reuse and -readability --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a07c7260f712c..0387708033b53 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2903,7 +2903,7 @@ impl NonNull { #[inline] pub fn new(ptr: *mut T) -> Option { if !ptr.is_null() { - Some(NonNull { pointer: unsafe { NonZero(ptr as _) } }) + Some(unsafe { Self::new_unchecked(ptr) }) } else { None } From 137a640d61a4c0fe3c88ae0062d1ae01faf8fbf5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 19 Nov 2018 15:24:03 +0100 Subject: [PATCH 17/23] Automatically generate imports for newtype_index `Deserialize` impls --- src/librustc/dep_graph/graph.rs | 1 - src/librustc/dep_graph/serialized.rs | 1 - src/librustc/hir/mod.rs | 1 - src/librustc/middle/region.rs | 1 - src/librustc/mir/mod.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/sty.rs | 2 +- src/librustc_data_structures/indexed_vec.rs | 24 ++++++++++++------- src/librustc_mir/borrow_check/location.rs | 1 - .../borrow_check/nll/constraints/mod.rs | 1 - .../borrow_check/nll/region_infer/values.rs | 1 - .../nll/type_check/liveness/liveness_map.rs | 1 - .../nll/type_check/liveness/local_use_map.rs | 1 - src/librustc_mir/build/mod.rs | 1 - src/librustc_target/abi/mod.rs | 1 - 15 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 06287bda63a49..4c94c993ab405 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -18,7 +18,6 @@ use std::env; use std::hash::Hash; use ty::{self, TyCtxt}; use util::common::{ProfileQueriesMsg, profq_msg}; -use serialize::{Decodable, Decoder}; use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs index 992ebd0efb15f..0c6c224fa914c 100644 --- a/src/librustc/dep_graph/serialized.rs +++ b/src/librustc/dep_graph/serialized.rs @@ -13,7 +13,6 @@ use dep_graph::DepNode; use ich::Fingerprint; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use serialize::{Decodable, Decoder}; newtype_index! { pub struct SerializedDepNodeIndex { .. } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 597a773821703..1674320165e65 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -122,7 +122,6 @@ impl serialize::UseSpecializedDecodable for HirId { // hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module mod item_local_id_inner { use rustc_data_structures::indexed_vec::Idx; - use serialize::{Decodable, Decoder}; /// An `ItemLocalId` uniquely identifies something within a given "item-like", /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no /// guarantee that the numerical value of a given `ItemLocalId` corresponds to diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 1440d91b47e63..35d1a4dd2cb7c 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -28,7 +28,6 @@ use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use ty::TyCtxt; use ty::query::Providers; -use serialize::{Decodable, Decoder}; use hir; use hir::Node; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 09b344cd38d25..4a463c0d5a394 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -25,7 +25,7 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::MappedReadGuard; -use rustc_serialize::{self as serialize, Decodable, Decoder}; +use rustc_serialize::{self as serialize}; use smallvec::SmallVec; use std::borrow::Cow; use std::fmt::{self, Debug, Formatter, Write}; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8ff93cee25022..4633ab1166347 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -41,7 +41,7 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use arena::SyncDroplessArena; use session::DataTypeKind; -use serialize::{self, Encodable, Encoder, Decodable, Decoder}; +use serialize::{self, Encodable, Encoder}; use std::cell::RefCell; use std::cmp::{self, Ordering}; use std::fmt; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index fa45b8c776837..1416cb17feaed 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -29,7 +29,7 @@ use rustc_target::spec::abi; use syntax::ast::{self, Ident}; use syntax::symbol::{keywords, InternedString}; -use serialize::{self, Decodable, Decoder}; +use serialize; use hir; diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index c35490ce35b4f..6522dbe117994 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -340,11 +340,7 @@ macro_rules! newtype_index { @vis [$v] @debug_format [$debug_format] $($tokens)*); - impl Decodable for $type { - fn decode(d: &mut D) -> Result { - d.read_u32().into() - } - } + newtype_index!(@decodable $type); ); // The case where no derives are added, but encodable is overridden. Don't @@ -377,9 +373,21 @@ macro_rules! newtype_index { @vis [$v] @debug_format [$debug_format] $($tokens)*); - impl Decodable for $type { - fn decode(d: &mut D) -> Result { - d.read_u32().map(Self::from) + newtype_index!(@decodable $type); + ); + + (@decodable $type:ident) => ( + impl $type { + fn __decodable__impl__hack() { + mod __more_hacks_because__self_doesnt_work_in_functions { + extern crate serialize; + use self::serialize::{Decodable, Decoder}; + impl Decodable for super::$type { + fn decode(d: &mut D) -> Result { + d.read_u32().map(Self::from) + } + } + } } } ); diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs index 2d593d851138b..b3e159dd84457 100644 --- a/src/librustc_mir/borrow_check/location.rs +++ b/src/librustc_mir/borrow_check/location.rs @@ -10,7 +10,6 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_serialize::{Decodable, Decoder}; /// Maps between a MIR Location, which identifies a particular /// statement within a basic block, to a "rich location", which diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index 37b11a77184d4..a873af8333a7f 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -13,7 +13,6 @@ use rustc::ty::RegionVid; use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use borrow_check::nll::type_check::Locations; -use rustc_serialize::{Decodable, Decoder}; use std::fmt; use std::ops::Deref; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 5ce80ca236dbb..69e2c896d33e5 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -16,7 +16,6 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt::Debug; use std::rc::Rc; -use rustc_serialize::{Decodable, Decoder}; /// Maps between a `Location` and a `PointIndex` (and vice versa). crate struct RegionValueElements { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs index d1a1d2aea248a..cc176cbc40392 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs @@ -23,7 +23,6 @@ use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use util::liveness::LiveVariableMap; -use rustc_serialize::{Decodable, Decoder}; /// Map between Local and LiveVar indices: the purpose of this /// map is to define the subset of local variables for which we need diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index 9e0eaf61e94a4..4b39d58cd96a8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -15,7 +15,6 @@ use rustc::mir::{Local, Location, Mir}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::vec_linked_list as vll; use util::liveness::{categorize, DefUse, LiveVariableMap}; -use rustc_serialize::{Decodable, Decoder}; /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1a5a089c7aa03..cc927df6350bd 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -32,7 +32,6 @@ use syntax::ast; use syntax::attr::{self, UnwindAttr}; use syntax::symbol::keywords; use syntax_pos::Span; -use rustc_serialize::{Decodable, Decoder}; use transform::MirSource; use util as mir_util; diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 27a4292543ad6..50ce0ad6915da 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -17,7 +17,6 @@ use std::fmt; use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_serialize::{Decodable, Decoder}; pub mod call; From ae0b00cadace32fd85c6786df24a20d6b55a87d2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 19 Nov 2018 15:24:23 +0100 Subject: [PATCH 18/23] Add and update tests --- src/test/run-pass-fulldeps/newtype_index.rs | 1 - .../ui/consts/min_const_fn/min_const_fn.rs | 6 ++-- .../min_const_fn/min_const_fn_unsafe.rs | 22 +++++++------- .../min_const_fn/min_const_fn_unsafe.stderr | 30 +++++++++---------- .../min_const_fn_unsafe_feature_gate.rs | 3 ++ .../min_const_fn_unsafe_feature_gate.stderr | 22 ++++++++++++-- src/test/ui/unsafe/ranged_ints4_const.rs | 4 +-- src/test/ui/unsafe/ranged_ints4_const.stderr | 23 ++------------ 8 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs index 4c5a21201d674..0fd7ccd55fb2d 100644 --- a/src/test/run-pass-fulldeps/newtype_index.rs +++ b/src/test/run-pass-fulldeps/newtype_index.rs @@ -2,7 +2,6 @@ #[macro_use] extern crate rustc_data_structures; extern crate rustc_serialize; -use rustc_serialize::{Decodable, Decoder}; use rustc_data_structures::indexed_vec::Idx; diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 0dba3a7de5378..43ca9e7539309 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -78,9 +78,9 @@ const fn i32_ops2(c: i32, d: i32) -> bool { c < d } const fn i32_ops3(c: i32, d: i32) -> bool { c != d } const fn i32_ops4(c: i32, d: i32) -> i32 { c + d } const fn char_cast(u: u8) -> char { u as char } -const unsafe fn foo4() -> i32 { 42 } -const unsafe fn foo5() -> *const T { 0 as *const T } -const unsafe fn foo6() -> *mut T { 0 as *mut T } +const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } +const unsafe fn ret_null_ptr_no_unsafe() -> *const T { 0 as *const T } +const unsafe fn ret_null_mut_ptr_no_unsafe() -> *mut T { 0 as *mut T } // not ok const fn foo11(t: T) -> T { t } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index 02a357551df30..f11b43dcd865c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -11,22 +11,24 @@ // gate-test-min_const_unsafe_fn // ok -const unsafe fn foo4() -> i32 { 42 } -const unsafe fn foo5() -> *const T { 0 as *const T } -const unsafe fn foo6() -> *mut T { 0 as *mut T } +const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } +const unsafe fn ret_null_ptr_no_unsafe() -> *const T { 0 as *const T } +const unsafe fn ret_null_mut_ptr_no_unsafe() -> *mut T { 0 as *mut T } const fn no_unsafe() { unsafe {} } // not ok -const fn foo8() -> i32 { - unsafe { foo4() } //~ ERROR calls to `const unsafe fn` in const fns are unstable +const fn call_unsafe_const_fn() -> i32 { + unsafe { ret_i32_no_unsafe() } //~ ERROR calls to `const unsafe fn` in const fns are unstable } -const fn foo9() -> *const String { - unsafe { foo5::() } //~ ERROR calls to `const unsafe fn` in const fns are unstable +const fn call_unsafe_generic_const_fn() -> *const String { + unsafe { ret_null_ptr_no_unsafe::() } + //~^ ERROR calls to `const unsafe fn` in const fns are unstable } -const fn foo10() -> *const Vec> { - unsafe { foo6::>>() } //~ ERROR calls to `const unsafe fn` in const fns +const fn call_unsafe_generic_cell_const_fn() -> *const Vec> { + unsafe { ret_null_mut_ptr_no_unsafe::>>() } + //~^ ERROR calls to `const unsafe fn` in const fns } -const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn //~^ dereferencing raw pointers in constant functions fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 0b8ff4717c128..8d885545cde56 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,13 +1,13 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe.rs:29:51 + --> $DIR/min_const_fn_unsafe.rs:31:59 | -LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn - | ^^ +LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn + | ^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe.rs:36:5 + --> $DIR/min_const_fn_unsafe.rs:38:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ @@ -17,37 +17,37 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:21:14 | -LL | unsafe { foo4() } //~ ERROR calls to `const unsafe fn` in const fns are unstable - | ^^^^^^ +LL | unsafe { ret_i32_no_unsafe() } //~ ERROR calls to `const unsafe fn` in const fns are unstable + | ^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:24:14 | -LL | unsafe { foo5::() } //~ ERROR calls to `const unsafe fn` in const fns are unstable - | ^^^^^^^^^^^^^^^^ +LL | unsafe { ret_null_ptr_no_unsafe::() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) - --> $DIR/min_const_fn_unsafe.rs:27:14 + --> $DIR/min_const_fn_unsafe.rs:28:14 | -LL | unsafe { foo6::>>() } //~ ERROR calls to `const unsafe fn` in const fns - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { ret_null_mut_ptr_no_unsafe::>>() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:29:51 + --> $DIR/min_const_fn_unsafe.rs:31:59 | -LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn - | ^^ dereference of raw pointer +LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn + | ^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:36:5 + --> $DIR/min_const_fn_unsafe.rs:38:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs index b66460d64089b..8a6884bc6b93c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs @@ -50,6 +50,9 @@ const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn //~^ dereferencing raw pointers in constant functions +const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed +//~^ dereferencing raw pointers in constant functions + fn main() {} const unsafe fn no_union() { diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr index d88ed1a5ad2cf..4336db65813b3 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr @@ -14,8 +14,16 @@ LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable +error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) + --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 + | +LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed + | ^^^ + | + = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable + error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:57:5 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ @@ -62,14 +70,22 @@ LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior +error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn + --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 + | +LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed + | ^^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:57:5 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5 | LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unsafe/ranged_ints4_const.rs b/src/test/ui/unsafe/ranged_ints4_const.rs index 09689579639e7..f589e4739baf1 100644 --- a/src/test/ui/unsafe/ranged_ints4_const.rs +++ b/src/test/ui/unsafe/ranged_ints4_const.rs @@ -7,13 +7,13 @@ fn main() {} const fn foo() -> NonZero { let mut x = unsafe { NonZero(1) }; - x.0 = 0; //~ ERROR statements in constant functions are unstable + x.0 = 0; //~^ ERROR mutation of layout constrained field is unsafe x } const fn bar() -> NonZero { let mut x = unsafe { NonZero(1) }; - unsafe { x.0 = 0 }; //~ ERROR statements in constant functions are unstable + unsafe { x.0 = 0 }; // this is UB x } diff --git a/src/test/ui/unsafe/ranged_ints4_const.stderr b/src/test/ui/unsafe/ranged_ints4_const.stderr index 284ba3603af2e..fe83b15ce5cec 100644 --- a/src/test/ui/unsafe/ranged_ints4_const.stderr +++ b/src/test/ui/unsafe/ranged_ints4_const.stderr @@ -1,28 +1,11 @@ -error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/ranged_ints4_const.rs:10:5 - | -LL | x.0 = 0; //~ ERROR statements in constant functions are unstable - | ^^^^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - -error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/ranged_ints4_const.rs:17:14 - | -LL | unsafe { x.0 = 0 }; //~ ERROR statements in constant functions are unstable - | ^^^^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints4_const.rs:10:5 | -LL | x.0 = 0; //~ ERROR statements in constant functions are unstable +LL | x.0 = 0; | ^^^^^^^ mutation of layout constrained field | = note: mutating layout constrained fields cannot statically be checked for valid values -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0133, E0658. -For more information about an error, try `rustc --explain E0133`. +For more information about this error, try `rustc --explain E0133`. From b75d5f18677fadef03cc55887a18c804af527d9f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 30 Nov 2018 18:07:51 +0100 Subject: [PATCH 19/23] Clean up the logic in `is_min_const_fn` --- src/librustc/ty/constness.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index f067a125c5dc9..d86170b24f239 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -40,19 +40,24 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// Returns true if this function must conform to `min_const_fn` pub fn is_min_const_fn(self, def_id: DefId) -> bool { - if self.features().staged_api { - // some intrinsics are waved through if called inside the - // standard library. Users never need to call them directly - if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() { - assert!(!self.is_const_fn(def_id)); - match &self.item_name(def_id).as_str()[..] { - | "size_of" - | "min_align_of" - | "needs_drop" - => return true, - _ => {}, - } + // some intrinsics are waved through if called inside the + // standard library. Users never need to call them directly + if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() { + match &self.item_name(def_id).as_str()[..] { + | "size_of" + | "min_align_of" + | "needs_drop" + => return true, + _ => {}, } + } + + // Bail out if the signature doesn't contain `const` + if !self.is_const_fn_raw(def_id) { + return false; + } + + if self.features().staged_api { // in order for a libstd function to be considered min_const_fn // it needs to be stable and have no `rustc_const_unstable` attribute self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) { @@ -66,7 +71,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } } else { // users enabling the `const_fn` feature gate can do what they want - self.is_const_fn_raw(def_id) && !self.features().const_fn + !self.features().const_fn } } } From 932dbe816e98d874ca1d7a7f0913ca9f67a94a84 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 30 Nov 2018 18:17:50 +0100 Subject: [PATCH 20/23] Explain unsafety trickery of const functions --- src/librustc_mir/build/mod.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index cc927df6350bd..054fb5f458117 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -114,11 +114,20 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t hir::Unsafety::Normal => Safety::Safe, hir::Unsafety::Unsafe => Safety::FnUnsafe, }; - let safety = if implicit_argument.is_none() && tcx.is_min_const_fn(fn_def_id) { - // the body of `const unsafe fn`s is treated like the body of safe `const fn`s - Safety::Safe - } else { - safety + + let safety = match fn_sig.unsafety { + hir::Unsafety::Normal => Safety::Safe, + hir::Unsafety::Unsafe => { + if tcx.is_min_const_fn(fn_def_id) => { + // As specified in #55607, a `const unsafe fn` differs + // from an `unsafe fn` in that its body is still considered + // safe code by default. + assert!(!implicit_argument.is_none()); + Safety::Safe + } else { + Safety::Unsafe + } + } }; let body = tcx.hir.body(body_id); From b77969466c23a51fdd7da25aa3ccc98e52d58d3b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 30 Nov 2018 18:18:42 +0100 Subject: [PATCH 21/23] Clear up some code --- src/librustc_mir/build/mod.rs | 23 ++++++-------------- src/librustc_mir/transform/check_unsafety.rs | 15 ++++++++----- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 054fb5f458117..1538c070f373a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -109,27 +109,18 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t _ => None, }; - // FIXME: safety in closures let safety = match fn_sig.unsafety { hir::Unsafety::Normal => Safety::Safe, + hir::Unsafety::Unsafe if tcx.is_min_const_fn(fn_def_id) => { + // As specified in #55607, a `const unsafe fn` differs + // from an `unsafe fn` in that its body is still considered + // safe code by default. + assert!(!implicit_argument.is_none()); + Safety::Safe + }, hir::Unsafety::Unsafe => Safety::FnUnsafe, }; - let safety = match fn_sig.unsafety { - hir::Unsafety::Normal => Safety::Safe, - hir::Unsafety::Unsafe => { - if tcx.is_min_const_fn(fn_def_id) => { - // As specified in #55607, a `const unsafe fn` differs - // from an `unsafe fn` in that its body is still considered - // safe code by default. - assert!(!implicit_argument.is_none()); - Safety::Safe - } else { - Safety::Unsafe - } - } - }; - let body = tcx.hir.body(body_id); let explicit_arguments = body.arguments diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 25dbd160d19f4..b47f1957ab4c9 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -351,19 +351,22 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } // only some unsafety is allowed in const fn if self.min_const_fn { + let min_const_unsafe_fn = self.tcx.features().min_const_unsafe_fn; for violation in violations { match violation.kind { - // these are allowed - UnsafetyViolationKind::GatedConstFnCall => { + UnsafetyViolationKind::GatedConstFnCall if min_const_unsafe_fn => { + // these function calls to unsafe functions are allowed // if `#![feature(min_const_unsafe_fn)]` is active - if !self.tcx.sess.features_untracked().min_const_unsafe_fn { - if !self.violations.contains(&violation) { - self.violations.push(violation.clone()) - } + }, + UnsafetyViolationKind::GatedConstFnCall => { + // without the feature gate, we report errors + if !self.violations.contains(&violation) { + self.violations.push(violation.clone()) } } // these unsafe things are stable in const fn UnsafetyViolationKind::GeneralAndConstFn => {}, + // these things are forbidden in const fns UnsafetyViolationKind::General | UnsafetyViolationKind::BorrowPacked(_) | UnsafetyViolationKind::ExternStatic(_) => { From f4115765c5ad16789e9ccdd49dca1a56d47f2b3f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 1 Dec 2018 14:09:30 +0100 Subject: [PATCH 22/23] Intrinsic checks are just needed for `qualify_min_const_fn` --- src/librustc/ty/constness.rs | 15 +------ src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/transform/check_unsafety.rs | 18 ++++++--- .../transform/qualify_min_const_fn.rs | 40 ++++++++++++++----- .../min_const_fn/min_const_fn_unsafe.stderr | 2 + .../min_const_fn_unsafe_feature_gate.stderr | 6 +++ 6 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index d86170b24f239..bc06167399533 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -5,7 +5,6 @@ use ty::TyCtxt; use syntax_pos::symbol::Symbol; use hir::map::blocks::FnLikeNode; use syntax::attr; -use rustc_target::spec::abi; impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// Whether the `def_id` counts as const fn in your current crate, considering all active @@ -40,18 +39,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// Returns true if this function must conform to `min_const_fn` pub fn is_min_const_fn(self, def_id: DefId) -> bool { - // some intrinsics are waved through if called inside the - // standard library. Users never need to call them directly - if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() { - match &self.item_name(def_id).as_str()[..] { - | "size_of" - | "min_align_of" - | "needs_drop" - => return true, - _ => {}, - } - } - // Bail out if the signature doesn't contain `const` if !self.is_const_fn_raw(def_id) { return false; @@ -60,7 +47,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { if self.features().staged_api { // in order for a libstd function to be considered min_const_fn // it needs to be stable and have no `rustc_const_unstable` attribute - self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) { + match self.lookup_stability(def_id) { // stable functions with unstable const fn aren't `min_const_fn` Some(&attr::Stability { const_stability: Some(_), .. }) => false, // unstable functions don't need to conform diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1538c070f373a..90a204ce00d53 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -115,7 +115,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t // As specified in #55607, a `const unsafe fn` differs // from an `unsafe fn` in that its body is still considered // safe code by default. - assert!(!implicit_argument.is_none()); + assert!(implicit_argument.is_none()); Safety::Safe }, hir::Unsafety::Unsafe => Safety::FnUnsafe, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index b47f1957ab4c9..75f8045cfae99 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -514,7 +514,7 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let param_env = tcx.param_env(def_id); let mut checker = UnsafetyChecker::new( - tcx.is_const_fn(def_id) && tcx.is_min_const_fn(def_id), + tcx.is_min_const_fn(def_id), mir, source_scope_local_data, tcx, param_env); checker.visit_mir(mir); @@ -617,13 +617,19 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { // Report an error. match kind { UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => { - tcx.sess.struct_span_err( + let mut err = tcx.sess.struct_span_err( source_info.span, &format!("{} is unsafe and unsafe operations \ - are not allowed in const fn", description)) - .span_label(source_info.span, &description.as_str()[..]) - .note(&details.as_str()[..]) - .emit(); + are not allowed in const fn", description)); + err.span_label(source_info.span, &description.as_str()[..]) + .note(&details.as_str()[..]); + if tcx.fn_sig(def_id).unsafety() == hir::Unsafety::Unsafe { + err.note( + "unsafe action within a `const unsafe fn` still require an `unsafe` \ + block in contrast to regular `unsafe fn`." + ); + } + err.emit(); } UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 13e134ba85928..3c1b9dbd91fa8 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -2,6 +2,7 @@ use rustc::hir::def_id::DefId; use rustc::hir; use rustc::mir::*; use rustc::ty::{self, Predicate, TyCtxt}; +use rustc_target::spec::abi; use std::borrow::Cow; use syntax_pos::Span; @@ -338,19 +339,40 @@ fn check_terminator( } => { let fn_ty = func.ty(mir, tcx); if let ty::FnDef(def_id, _) = fn_ty.sty { - if tcx.is_min_const_fn(def_id) { - check_operand(tcx, mir, func, span)?; - for arg in args { - check_operand(tcx, mir, arg, span)?; - } - Ok(()) - } else { - Err(( + // some intrinsics are waved through if called inside the + // standard library. Users never need to call them directly + match tcx.fn_sig(def_id).abi() { + abi::Abi::RustIntrinsic => match &tcx.item_name(def_id).as_str()[..] { + | "size_of" + | "min_align_of" + | "needs_drop" + => {}, + _ => return Err(( + span, + "can only call a curated list of intrinsics in `min_const_fn`".into(), + )), + }, + abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {}, + abi::Abi::Rust => return Err(( span, "can only call other `min_const_fn` within a `min_const_fn`".into(), - )) + )), + abi => return Err(( + span, + format!( + "cannot call functions with `{}` abi in `min_const_fn`", + abi, + ).into(), + )), + } + + check_operand(tcx, mir, func, span)?; + + for arg in args { + check_operand(tcx, mir, arg, span)?; } + Ok(()) } else { Err((span, "can only call other const fns within const fn".into())) } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 8d885545cde56..922a7883b9f2d 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -45,6 +45,7 @@ LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR no | ^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: access to union field is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe.rs:38:5 @@ -53,6 +54,7 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: aborting due to 7 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr index 4336db65813b3..20c75afbe638b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr @@ -37,6 +37,7 @@ LL | foo4() //~ ERROR not allowed in const fn | ^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:42:5 @@ -45,6 +46,7 @@ LL | foo5::() //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:45:5 @@ -53,6 +55,7 @@ LL | foo6::>>() //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 @@ -61,6 +64,7 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe | ^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 @@ -69,6 +73,7 @@ LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR | ^^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 @@ -85,6 +90,7 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: aborting due to 11 previous errors From cb71752f911c47426e208a9f5f1862d4c0e56aa4 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 4 Dec 2018 11:04:54 +0100 Subject: [PATCH 23/23] Tidy fixup --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 026b159f80f9a..bfdc75378d5e1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -492,7 +492,7 @@ declare_features! ( // `extern crate self as foo;` puts local crate root into extern prelude under name `foo`. (active, extern_crate_self, "1.31.0", Some(56409), None), - + // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. (active, min_const_unsafe_fn, "1.31.0", Some(55607), None), );