From 2b98349cdde6c8e073f35de26f6740f5df83c200 Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Fri, 11 Apr 2014 16:04:21 +0200 Subject: [PATCH 1/3] Allow some unused unsafes until the next snapshot cc #13232 --- src/libgreen/lib.rs | 1 + src/liblog/lib.rs | 2 ++ src/librustc/middle/trans/debuginfo.rs | 1 + src/librustc/middle/ty.rs | 4 ++++ src/libstd/io/tempfile.rs | 1 + src/libstd/io/test.rs | 2 ++ src/libstd/os.rs | 2 ++ src/libstd/rt/backtrace.rs | 1 + src/libstd/rt/bookkeeping.rs | 1 + src/libstd/rt/env.rs | 4 ++++ src/libstd/rt/local_ptr.rs | 2 ++ src/test/run-pass/ifmt.rs | 1 + 12 files changed, 22 insertions(+) diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs index 820627b6b7d13..fafe5160cf91e 100644 --- a/src/libgreen/lib.rs +++ b/src/libgreen/lib.rs @@ -344,6 +344,7 @@ impl SchedPool { /// /// This will configure the pool according to the `config` parameter, and /// initially run `main` inside the pool of schedulers. + #[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn new(config: PoolConfig) -> SchedPool { static mut POOL_ID: AtomicUint = INIT_ATOMIC_UINT; diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 0656dd1f64163..591732083efcb 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -213,6 +213,7 @@ pub fn log(level: u32, args: &fmt::Arguments) { /// safely #[doc(hidden)] #[inline(always)] +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn log_level() -> u32 { unsafe { LOG_LEVEL } } /// Replaces the task-local logger with the specified logger, returning the old @@ -227,6 +228,7 @@ pub fn set_logger(logger: ~Logger:Send) -> Option<~Logger:Send> { /// logging. This is the second layer of defense about determining whether a /// module's log statement should be emitted or not. #[doc(hidden)] +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn mod_enabled(level: u32, module: &str) -> bool { static mut INIT: Once = ONCE_INIT; unsafe { INIT.doit(init); } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 1b3be8d29f33c..2e14b59b3560c 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -2307,6 +2307,7 @@ fn cache_id_for_type(t: ty::t) -> uint { // Used to avoid LLVM metadata uniquing problems. See `create_struct_stub()` and // `prepare_enum_metadata()`. +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) fn generate_unique_type_id(prefix: &'static str) -> ~str { unsafe { static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index aac847c795aeb..eb9e54ca3a2fb 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1989,6 +1989,10 @@ pub fn type_is_sendable(cx: &ctxt, t: ty::t) -> bool { type_contents(cx, t).is_sendable(cx) } +pub fn type_is_sharable(cx: &ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_sharable(cx) +} + pub fn type_interior_is_unsafe(cx: &ctxt, t: ty::t) -> bool { type_contents(cx, t).interior_unsafe() } diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs index 4ff1c7faaece2..d65309eb1026a 100644 --- a/src/libstd/io/tempfile.rs +++ b/src/libstd/io/tempfile.rs @@ -33,6 +33,7 @@ impl TempDir { /// deleted once the returned wrapper is destroyed. /// /// If no directory can be created, None is returned. + #[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn new_in(tmpdir: &Path, suffix: &str) -> Option { if !tmpdir.is_absolute() { return TempDir::new_in(&os::make_absolute(tmpdir), suffix); diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs index dd874fecc52a5..085e0e20e1554 100644 --- a/src/libstd/io/test.rs +++ b/src/libstd/io/test.rs @@ -54,6 +54,7 @@ macro_rules! iotest ( ) /// Get a port number, starting at 9600, for use in tests +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn next_test_port() -> u16 { static mut next_offset: AtomicUint = INIT_ATOMIC_UINT; unsafe { @@ -62,6 +63,7 @@ pub fn next_test_port() -> u16 { } /// Get a temporary path which could be the location of a unix socket +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn next_test_unix() -> Path { static mut COUNT: AtomicUint = INIT_ATOMIC_UINT; // base port and pid are an attempt to be unique between multiple diff --git a/src/libstd/os.rs b/src/libstd/os.rs index a16113cb48fce..01a063a7f2092 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -781,12 +781,14 @@ static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT; * * Note that this is not synchronized against modifications of other threads. */ +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn set_exit_status(code: int) { unsafe { EXIT_STATUS.store(code, SeqCst) } } /// Fetches the process's current exit code. This defaults to 0 and can change /// by calling `set_exit_status`. +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn get_exit_status() -> int { unsafe { EXIT_STATUS.load(SeqCst) } } diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index bf8c15c20abbd..b0aaa1c2dcd64 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -25,6 +25,7 @@ pub use self::imp::write; // For now logging is turned off by default, and this function checks to see // whether the magical environment variable is present to see if it's turned on. +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn log_enabled() -> bool { static mut ENABLED: atomics::AtomicInt = atomics::INIT_ATOMIC_INT; unsafe { diff --git a/src/libstd/rt/bookkeeping.rs b/src/libstd/rt/bookkeeping.rs index 9e772d8ad2385..a6f0ebfdc334d 100644 --- a/src/libstd/rt/bookkeeping.rs +++ b/src/libstd/rt/bookkeeping.rs @@ -27,6 +27,7 @@ use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn increment() { let _ = unsafe { TASK_COUNT.fetch_add(1, atomics::SeqCst) }; } diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs index 94f56d42613fd..5632f5a1aea13 100644 --- a/src/libstd/rt/env.rs +++ b/src/libstd/rt/env.rs @@ -22,6 +22,7 @@ static mut MIN_STACK: uint = 2 * 1024 * 1024; static mut MAX_CACHED_STACKS: uint = 10; static mut DEBUG_BORROW: bool = false; +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn init() { unsafe { match os::getenv("RUST_MIN_STACK") { @@ -43,14 +44,17 @@ pub fn init() { } } +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn min_stack() -> uint { unsafe { MIN_STACK } } +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn max_cached_stacks() -> uint { unsafe { MAX_CACHED_STACKS } } +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn debug_borrow() -> bool { unsafe { DEBUG_BORROW } } diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs index e3f64f40c0d40..9c9ba1e63969e 100644 --- a/src/libstd/rt/local_ptr.rs +++ b/src/libstd/rt/local_ptr.rs @@ -200,6 +200,7 @@ pub mod compiled { /// Check whether there is a thread-local pointer installed. #[inline(never)] // see comments above + #[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn exists() -> bool { unsafe { RT_TLS_PTR.is_not_null() @@ -367,6 +368,7 @@ pub mod native { #[inline] #[cfg(not(test))] #[allow(visible_private_types)] + #[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) pub fn maybe_tls_key() -> Option { unsafe { // NB: This is a little racy because, while the key is diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 17c54780fa28b..092e7ebd50e53 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -204,6 +204,7 @@ fn test_format_args() { t!(s, "hello world"); } +#[allow(unused_unsafe)] // NOTE: Remove after next snapshot (and the unsafe block) fn test_order() { // Make sure format!() arguments are always evaluated in a left-to-right // ordering From e04c03dff531e4dbd630a1ffad30110abea5c324 Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Fri, 11 Apr 2014 11:39:05 +0200 Subject: [PATCH 2/3] Use a visitor env instead of an instance flag Instead of having an `unsafe_block` field in the `EffectVisitor`, use an env to hold this information. Envs are clone before walking a sub-expression, this helps keeping flags isolated and per-expression. --- src/librustc/middle/effect.rs | 60 ++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 827d07484b739..2480fc974ae76 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -20,7 +20,7 @@ use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; -#[deriving(Eq)] +#[deriving(Eq, Clone)] enum UnsafeContext { SafeContext, UnsafeFn, @@ -35,18 +35,22 @@ fn type_is_unsafe_function(ty: ty::t) -> bool { } } +#[deriving(Eq, Clone)] +struct EffectEnv { + /// Whether we're in an unsafe context. + unsafe_context: UnsafeContext +} + struct EffectCheckVisitor<'a> { tcx: &'a ty::ctxt, /// The method map. method_map: MethodMap, - /// Whether we're in an unsafe context. - unsafe_context: UnsafeContext, } impl<'a> EffectCheckVisitor<'a> { - fn require_unsafe(&mut self, span: Span, description: &str) { - match self.unsafe_context { + fn require_unsafe(&mut self, span: Span, env: &EffectEnv, description: &str) { + match env.unsafe_context { SafeContext => { // Report an error. self.tcx.sess.span_err(span, @@ -79,9 +83,9 @@ impl<'a> EffectCheckVisitor<'a> { } } -impl<'a> Visitor<()> for EffectCheckVisitor<'a> { +impl<'a> Visitor for EffectCheckVisitor<'a> { fn visit_fn(&mut self, fn_kind: &visit::FnKind, fn_decl: &ast::FnDecl, - block: &ast::Block, span: Span, node_id: ast::NodeId, _:()) { + block: &ast::Block, span: Span, node_id: ast::NodeId, env: EffectEnv) { let (is_item_fn, is_unsafe_fn) = match *fn_kind { visit::FkItemFn(_, _, fn_style, _) => @@ -91,20 +95,19 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { _ => (false, false), }; - let old_unsafe_context = self.unsafe_context; + let mut env = env; + if is_unsafe_fn { - self.unsafe_context = UnsafeFn + env.unsafe_context = UnsafeFn; } else if is_item_fn { - self.unsafe_context = SafeContext + env.unsafe_context = SafeContext; } - visit::walk_fn(self, fn_kind, fn_decl, block, span, node_id, ()); - - self.unsafe_context = old_unsafe_context + visit::walk_fn(self, fn_kind, fn_decl, block, span, node_id, env); } - fn visit_block(&mut self, block: &ast::Block, _:()) { - let old_unsafe_context = self.unsafe_context; + fn visit_block(&mut self, block: &ast::Block, env: EffectEnv) { + let mut env = env; match block.rules { ast::DefaultBlock => {} ast::UnsafeBlock(source) => { @@ -123,18 +126,16 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { // external blocks (e.g. `unsafe { println("") }`, // expands to `unsafe { ... unsafe { ... } }` where // the inner one is compiler generated). - if self.unsafe_context == SafeContext || source == ast::CompilerGenerated { - self.unsafe_context = UnsafeBlock(block.id) + if env.unsafe_context == SafeContext || source == ast::CompilerGenerated { + env.unsafe_context = UnsafeBlock(block.id); } } } - visit::walk_block(self, block, ()); - - self.unsafe_context = old_unsafe_context + visit::walk_block(self, block, env); } - fn visit_expr(&mut self, expr: &ast::Expr, _:()) { + fn visit_expr(&mut self, expr: &ast::Expr, env: EffectEnv) { match expr.node { ast::ExprMethodCall(_, _, _) => { let method_call = MethodCall::expr(expr.id); @@ -142,7 +143,7 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { debug!("effect: method call case, base type is {}", ppaux::ty_to_str(self.tcx, base_type)); if type_is_unsafe_function(base_type) { - self.require_unsafe(expr.span, + self.require_unsafe(expr.span, &env, "invocation of unsafe method") } } @@ -151,7 +152,7 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { debug!("effect: call case, base type is {}", ppaux::ty_to_str(self.tcx, base_type)); if type_is_unsafe_function(base_type) { - self.require_unsafe(expr.span, "call to unsafe function") + self.require_unsafe(expr.span, &env, "call to unsafe function") } } ast::ExprUnary(ast::UnDeref, base) => { @@ -160,7 +161,7 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { ppaux::ty_to_str(self.tcx, base_type)); match ty::get(base_type).sty { ty::ty_ptr(_) => { - self.require_unsafe(expr.span, + self.require_unsafe(expr.span, &env, "dereference of unsafe pointer") } _ => {} @@ -173,12 +174,12 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { self.check_str_index(base); } ast::ExprInlineAsm(..) => { - self.require_unsafe(expr.span, "use of inline assembly") + self.require_unsafe(expr.span, &env, "use of inline assembly") } ast::ExprPath(..) => { match ty::resolve_expr(self.tcx, expr) { ast::DefStatic(_, true) => { - self.require_unsafe(expr.span, "use of mutable static") + self.require_unsafe(expr.span, &env, "use of mutable static") } _ => {} } @@ -186,7 +187,7 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { _ => {} } - visit::walk_expr(self, expr, ()); + visit::walk_expr(self, expr, env); } } @@ -194,8 +195,9 @@ pub fn check_crate(tcx: &ty::ctxt, method_map: MethodMap, krate: &ast::Crate) { let mut visitor = EffectCheckVisitor { tcx: tcx, method_map: method_map, - unsafe_context: SafeContext, }; - visit::walk_crate(&mut visitor, krate, ()); + let env = EffectEnv{unsafe_context: SafeContext}; + + visit::walk_crate(&mut visitor, krate, env); } From 1d0fa72ebf09ff68b275d4d4fbf7b046056c0d11 Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Fri, 11 Apr 2014 16:00:16 +0200 Subject: [PATCH 3/3] Allow taking `&`-pointers of `Share` mut static items In general, it's not allowed to access mutable static items outside an unsafe block. However, taking an immutable address of a mutable static items whose type implements `Share` is considered a safe operation. This is enforced by `rustc::middle::effect` Closes #13232 --- src/librustc/middle/check_static.rs | 7 +- src/librustc/middle/effect.rs | 83 +++++++++++++++++-- .../effect-noshare-mut-static-unsafe.rs | 67 +++++++++++++++ .../static-mut-foreign-requires-unsafe.rs | 19 +++-- .../static-mut-requires-unsafe.rs | 17 ---- .../run-pass/effect-share-static-mut-safe.rs | 42 ++++++++++ 6 files changed, 203 insertions(+), 32 deletions(-) create mode 100644 src/test/compile-fail/effect-noshare-mut-static-unsafe.rs delete mode 100644 src/test/compile-fail/static-mut-requires-unsafe.rs create mode 100644 src/test/run-pass/effect-share-static-mut-safe.rs diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index ecc3ba59dd5ab..bd4a06d8efa30 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -22,7 +22,12 @@ // // Rules Enforced Elsewhere: // - It's not possible to take the address of a static item with unsafe interior. This is enforced -// by borrowck::gather_loans +// by `rustc::middle::borrowck::gather_loans` +// +// Mutable static items: +// In general, it's not allowed to access mutable static items outside an unsafe block. However, +// taking an immutable address of a mutable static items whose type implements `Share` is considered +// a safe operation. This is enforced by `rustc::middle::effect` use middle::ty; diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 2480fc974ae76..5baed21c2a6da 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -17,6 +17,7 @@ use util::ppaux; use syntax::ast; use syntax::codemap::Span; +use syntax::print::pprust; use syntax::visit; use syntax::visit::Visitor; @@ -38,7 +39,11 @@ fn type_is_unsafe_function(ty: ty::t) -> bool { #[deriving(Eq, Clone)] struct EffectEnv { /// Whether we're in an unsafe context. - unsafe_context: UnsafeContext + unsafe_context: UnsafeContext, + + /// Whether mut static usage should + /// be forbidden regardless. + allow_share: bool, } struct EffectCheckVisitor<'a> { @@ -81,6 +86,13 @@ impl<'a> EffectCheckVisitor<'a> { _ => {} } } + + fn expr_is_mut_static(&mut self, e: &ast::Expr) -> bool { + match self.tcx.def_map.borrow().find(&e.id) { + Some(&ast::DefStatic(_, true)) => true, + _ => false + } + } } impl<'a> Visitor for EffectCheckVisitor<'a> { @@ -136,8 +148,11 @@ impl<'a> Visitor for EffectCheckVisitor<'a> { } fn visit_expr(&mut self, expr: &ast::Expr, env: EffectEnv) { + let mut env = env; + debug!("visit_expr(expr={}, allow_share={})", + pprust::expr_to_str(expr), env.allow_share); match expr.node { - ast::ExprMethodCall(_, _, _) => { + ast::ExprMethodCall(_, _, ref args) => { let method_call = MethodCall::expr(expr.id); let base_type = self.method_map.borrow().get(&method_call).ty; debug!("effect: method call case, base type is {}", @@ -146,6 +161,30 @@ impl<'a> Visitor for EffectCheckVisitor<'a> { self.require_unsafe(expr.span, &env, "invocation of unsafe method") } + + // This is a method call, hence we just check the first + // expression in the call args which corresponds `Self` + if self.expr_is_mut_static(*args.get(0)) { + let adj_ty = ty::expr_ty_adjusted(self.tcx, *args.get(0), + &*self.method_map.borrow()); + match ty::get(adj_ty).sty { + ty::ty_rptr(_, mt) if mt.mutbl == ast::MutMutable => { + self.require_unsafe(expr.span, &env, + "mutable borrow of mutable static"); + } + _ => {} + } + } + + env.allow_share = true; + } + ast::ExprIndex(base, index) => { + self.visit_expr(base, env.clone()); + + // It is safe to access share static mut + // in index expressions. + env.allow_share = true; + return self.visit_expr(index, env); } ast::ExprCall(base, _) => { let base_type = ty::node_id_to_type(self.tcx, base.id); @@ -154,6 +193,8 @@ impl<'a> Visitor for EffectCheckVisitor<'a> { if type_is_unsafe_function(base_type) { self.require_unsafe(expr.span, &env, "call to unsafe function") } + + env.allow_share = true; } ast::ExprUnary(ast::UnDeref, base) => { let base_type = ty::node_id_to_type(self.tcx, base.id); @@ -167,21 +208,42 @@ impl<'a> Visitor for EffectCheckVisitor<'a> { _ => {} } } - ast::ExprAssign(base, _) | ast::ExprAssignOp(_, base, _) => { - self.check_str_index(base); + ast::ExprAssign(lhs, rhs) | ast::ExprAssignOp(_, lhs, rhs) => { + self.check_str_index(lhs); + + debug!("assign(rhs={}, lhs={})", + pprust::expr_to_str(rhs), + pprust::expr_to_str(lhs)) + + env.allow_share = true; + self.visit_expr(rhs, env.clone()); + + // we want to ignore `Share` statics + // *just* in the LHS of the assignment. + env.allow_share = false; + return self.visit_expr(lhs, env); + } + ast::ExprAddrOf(ast::MutImmutable, _) => { + env.allow_share = true; } ast::ExprAddrOf(ast::MutMutable, base) => { + if self.expr_is_mut_static(base) { + self.require_unsafe(expr.span, &env, + "mutable borrow of mutable static"); + } + self.check_str_index(base); + env.allow_share = true; } ast::ExprInlineAsm(..) => { self.require_unsafe(expr.span, &env, "use of inline assembly") } ast::ExprPath(..) => { - match ty::resolve_expr(self.tcx, expr) { - ast::DefStatic(_, true) => { - self.require_unsafe(expr.span, &env, "use of mutable static") + if self.expr_is_mut_static(expr) { + let ety = ty::node_id_to_type(self.tcx, expr.id); + if !env.allow_share || !ty::type_is_sharable(self.tcx, ety) { + self.require_unsafe(expr.span, &env, "this use of mutable static"); } - _ => {} } } _ => {} @@ -197,7 +259,10 @@ pub fn check_crate(tcx: &ty::ctxt, method_map: MethodMap, krate: &ast::Crate) { method_map: method_map, }; - let env = EffectEnv{unsafe_context: SafeContext}; + let env = EffectEnv{ + allow_share: false, + unsafe_context: SafeContext, + }; visit::walk_crate(&mut visitor, krate, env); } diff --git a/src/test/compile-fail/effect-noshare-mut-static-unsafe.rs b/src/test/compile-fail/effect-noshare-mut-static-unsafe.rs new file mode 100644 index 0000000000000..d08444e66e8f1 --- /dev/null +++ b/src/test/compile-fail/effect-noshare-mut-static-unsafe.rs @@ -0,0 +1,67 @@ +// Copyright 2014 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. + + +/// Verify that mutable static items that are not Share can't be addressed without +/// an `unsafe` block. + +use std::kinds::marker; + +struct NonSharable { + field: uint, + noshare: marker::NoShare +} + +struct Sharable { + field: uint +} + +impl Sharable { + fn foo(&self) {} + fn foo_mut(&mut self) {} +} + +static mut MyNonSharable: NonSharable = NonSharable { field: 1, noshare: marker::NoShare }; + +static mut MySharable: Sharable = Sharable { field: 0 }; + +pub fn fn_mut(_: &mut Sharable) {} + + +pub fn main() { + MySharable.foo(); + + MySharable.foo_mut(); + //~^ ERROR mutable borrow of mutable static requires unsafe function or bloc + + MySharable.field = 2; + //~^ ERROR: this use of mutable static requires unsafe function or block + + fn_mut(&mut MySharable); + //~^ ERROR mutable borrow of mutable static requires unsafe function or block + + MyNonSharable.field = 2; + //~^ ERROR: this use of mutable static requires unsafe function or block + + MySharable = Sharable {field: 1}; + //~^ ERROR: this use of mutable static requires unsafe function or block + + let _: &mut Sharable = &mut MySharable; + //~^ ERROR mutable borrow of mutable static requires unsafe function or block + + let _ = &MyNonSharable.field; + //~^ ERROR: this use of mutable static requires unsafe function or block + + let mut slc = ['a', 'c']; + slc[MyNonSharable.field] = 'b'; + //~^ ERROR: this use of mutable static requires unsafe function or block + + slc[MySharable.field] = 'b'; +} diff --git a/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs b/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs index 0e44af19a7f62..6eb2ca466608c 100644 --- a/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs +++ b/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs @@ -8,14 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate libc; + + +mod test { + use std::kinds::marker; + + pub struct NonSharable { + pub field: uint, + noshare: marker::NoShare + } +} extern { - static mut a: libc::c_int; + static mut a: test::NonSharable; } fn main() { - a += 3; //~ ERROR: requires unsafe - a = 4; //~ ERROR: requires unsafe - let _b = a; //~ ERROR: requires unsafe + a.field += 3; //~ ERROR: this use of mutable static requires unsafe function or block + a.field = 4; //~ ERROR: this use of mutable static requires unsafe function or block + let _b = a; //~ ERROR: this use of mutable static requires unsafe function or block } diff --git a/src/test/compile-fail/static-mut-requires-unsafe.rs b/src/test/compile-fail/static-mut-requires-unsafe.rs deleted file mode 100644 index 7337920cce68c..0000000000000 --- a/src/test/compile-fail/static-mut-requires-unsafe.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 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. - -static mut a: int = 3; - -fn main() { - a += 3; //~ ERROR: requires unsafe - a = 4; //~ ERROR: requires unsafe - let _b = a; //~ ERROR: requires unsafe -} diff --git a/src/test/run-pass/effect-share-static-mut-safe.rs b/src/test/run-pass/effect-share-static-mut-safe.rs new file mode 100644 index 0000000000000..5e42db55ccb4d --- /dev/null +++ b/src/test/run-pass/effect-share-static-mut-safe.rs @@ -0,0 +1,42 @@ +// Copyright 2014 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. + + +/// Verify that mutable static items that are Share can be addressed without +/// an `unsafe` block. + +struct Sharable { + field: uint +} + +impl Sharable { + fn foo(&self) {} + fn foo_mut(&mut self) {} +} + +static mut MySharable: Sharable = Sharable { field: 1}; + +fn borrow_static(_: &Sharable) {} + +pub fn main() { + + MySharable.foo(); + + borrow_static(&MySharable); + + let _ = &MySharable; + + unsafe { let _: &mut Sharable = &mut MySharable; } + + let mut slc = ['a', 'c']; + slc[MySharable.field] = 'b'; + + let _ = &((((MySharable)))); +}