提交 5ec11838 编写于 作者: H Huon Wilson

rustc: avoid compiler generated `unsafe` blocks leaking.

Previously an `unsafe` block created by the compiler (like those in the
formatting macros) would be "ignored" if surrounded by `unsafe`, that
is, the internal unsafety would be being legitimised by the external
block:

    unsafe { println!("...") } =(expansion)=> unsafe { ... unsafe { ... } }

And the code in the inner block would be using the outer block, making
it considered used (and the inner one considered unused).

This patch forces the compiler to create a new unsafe context for
compiler generated blocks, so that their internal unsafety doesn't
escape to external blocks.

Fixes #12418.
上级 c4afcf44
...@@ -106,11 +106,28 @@ fn visit_fn(&mut self, fn_kind: &visit::FnKind, fn_decl: &ast::FnDecl, ...@@ -106,11 +106,28 @@ fn visit_fn(&mut self, fn_kind: &visit::FnKind, fn_decl: &ast::FnDecl,
fn visit_block(&mut self, block: &ast::Block, _:()) { fn visit_block(&mut self, block: &ast::Block, _:()) {
let old_unsafe_context = self.unsafe_context; let old_unsafe_context = self.unsafe_context;
let is_unsafe = match block.rules { match block.rules {
ast::UnsafeBlock(..) => true, ast::DefaultBlock => false ast::DefaultBlock => {}
}; ast::UnsafeBlock(source) => {
if is_unsafe && self.unsafe_context == SafeContext { // By default only the outermost `unsafe` block is
self.unsafe_context = UnsafeBlock(block.id) // "used" and so nested unsafe blocks are pointless
// (the inner ones are unnecessary and we actually
// warn about them). As such, there are two cases when
// we need to create a new context, when we're
// - outside `unsafe` and found a `unsafe` block
// (normal case)
// - inside `unsafe` but found an `unsafe` block
// created internally to the compiler
//
// The second case is necessary to ensure that the
// compiler `unsafe` blocks don't accidentally "use"
// 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)
}
}
} }
visit::walk_block(self, block, ()); visit::walk_block(self, block, ());
......
...@@ -924,11 +924,9 @@ pub fn invoke<'a>( ...@@ -924,11 +924,9 @@ pub fn invoke<'a>(
} }
if need_invoke(bcx) { if need_invoke(bcx) {
unsafe { debug!("invoking {} at {}", llfn, bcx.llbb);
debug!("invoking {} at {}", llfn, bcx.llbb); for &llarg in llargs.iter() {
for &llarg in llargs.iter() { debug!("arg: {}", llarg);
debug!("arg: {}", llarg);
}
} }
let normal_bcx = bcx.fcx.new_temp_block("normal-return"); let normal_bcx = bcx.fcx.new_temp_block("normal-return");
let landing_pad = bcx.fcx.get_landing_pad(); let landing_pad = bcx.fcx.get_landing_pad();
...@@ -946,11 +944,9 @@ pub fn invoke<'a>( ...@@ -946,11 +944,9 @@ pub fn invoke<'a>(
attributes); attributes);
return (llresult, normal_bcx); return (llresult, normal_bcx);
} else { } else {
unsafe { debug!("calling {} at {}", llfn, bcx.llbb);
debug!("calling {} at {}", llfn, bcx.llbb); for &llarg in llargs.iter() {
for &llarg in llargs.iter() { debug!("arg: {}", llarg);
debug!("arg: {}", llarg);
}
} }
match call_info { match call_info {
......
...@@ -992,9 +992,7 @@ fn anon_regions(&self, span: Span, count: uint) ...@@ -992,9 +992,7 @@ fn anon_regions(&self, span: Span, count: uint)
impl FnCtxt { impl FnCtxt {
pub fn tag(&self) -> ~str { pub fn tag(&self) -> ~str {
unsafe { format!("{}", self as *FnCtxt)
format!("{}", self as *FnCtxt)
}
} }
pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t { pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
......
...@@ -486,14 +486,12 @@ pub fn abort_selection(&mut self, _was_upgrade: bool) -> bool { ...@@ -486,14 +486,12 @@ pub fn abort_selection(&mut self, _was_upgrade: bool) -> bool {
#[unsafe_destructor] #[unsafe_destructor]
impl<T: Send> Drop for Packet<T> { impl<T: Send> Drop for Packet<T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { // Note that this load is not only an assert for correctness about
// Note that this load is not only an assert for correctness about // disconnection, but also a proper fence before the read of
// disconnection, but also a proper fence before the read of // `to_wake`, so this assert cannot be removed with also removing
// `to_wake`, so this assert cannot be removed with also removing // the `to_wake` assert.
// the `to_wake` assert. assert_eq!(self.cnt.load(atomics::SeqCst), DISCONNECTED);
assert_eq!(self.cnt.load(atomics::SeqCst), DISCONNECTED); assert_eq!(self.to_wake.load(atomics::SeqCst), 0);
assert_eq!(self.to_wake.load(atomics::SeqCst), 0); assert_eq!(self.channels.load(atomics::SeqCst), 0);
assert_eq!(self.channels.load(atomics::SeqCst), 0);
}
} }
} }
...@@ -471,13 +471,11 @@ pub fn abort_selection(&mut self, ...@@ -471,13 +471,11 @@ pub fn abort_selection(&mut self,
#[unsafe_destructor] #[unsafe_destructor]
impl<T: Send> Drop for Packet<T> { impl<T: Send> Drop for Packet<T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { // Note that this load is not only an assert for correctness about
// Note that this load is not only an assert for correctness about // disconnection, but also a proper fence before the read of
// disconnection, but also a proper fence before the read of // `to_wake`, so this assert cannot be removed with also removing
// `to_wake`, so this assert cannot be removed with also removing // the `to_wake` assert.
// the `to_wake` assert. assert_eq!(self.cnt.load(atomics::SeqCst), DISCONNECTED);
assert_eq!(self.cnt.load(atomics::SeqCst), DISCONNECTED); assert_eq!(self.to_wake.load(atomics::SeqCst), 0);
assert_eq!(self.to_wake.load(atomics::SeqCst), 0);
}
} }
} }
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// issue #12418
#[deny(unused_unsafe)];
fn main() {
unsafe { println!("foo"); } //~ ERROR unnecessary `unsafe`
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册