auto merge of #5797 : alexcrichton/rust/issue-1913, r=catamorphism

Closes #5487, #1913, and #4568

I tracked this by adding all used unsafe blocks/functions to a set on the `tcx` passed around, and then when the lint pass comes around if an unsafe block/function isn't listed in that set, it's unused.

I also removed everything from the compiler that was unused, and up to stage2 is now compiling without any known unused unsafe blocks.

I chose `unused_unsafe` as the name of the lint attribute, but there may be a better name...
This commit is contained in:
bors 2013-04-15 13:00:56 -07:00
commit 4beebc427c
42 changed files with 1052 additions and 992 deletions

View File

@ -30,36 +30,34 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] {
}
fn parse_expected(line_num: uint, line: ~str) -> ~[ExpectedError] {
unsafe {
let error_tag = ~"//~";
let mut idx;
match str::find_str(line, error_tag) {
None => return ~[],
Some(nn) => { idx = (nn as uint) + str::len(error_tag); }
}
// "//~^^^ kind msg" denotes a message expected
// three lines above current line:
let mut adjust_line = 0u;
let len = str::len(line);
while idx < len && line[idx] == ('^' as u8) {
adjust_line += 1u;
idx += 1u;
}
// Extract kind:
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
let start_kind = idx;
while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
let kind = str::to_lower(str::slice(line, start_kind, idx).to_owned());
// Extract msg:
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
let msg = str::slice(line, idx, len).to_owned();
debug!("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg);
return ~[ExpectedError{line: line_num - adjust_line, kind: kind,
msg: msg}];
let error_tag = ~"//~";
let mut idx;
match str::find_str(line, error_tag) {
None => return ~[],
Some(nn) => { idx = (nn as uint) + str::len(error_tag); }
}
// "//~^^^ kind msg" denotes a message expected
// three lines above current line:
let mut adjust_line = 0u;
let len = str::len(line);
while idx < len && line[idx] == ('^' as u8) {
adjust_line += 1u;
idx += 1u;
}
// Extract kind:
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
let start_kind = idx;
while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
let kind = str::to_lower(str::slice(line, start_kind, idx).to_owned());
// Extract msg:
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
let msg = str::slice(line, idx, len).to_owned();
debug!("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg);
return ~[ExpectedError{line: line_num - adjust_line, kind: kind,
msg: msg}];
}

View File

@ -171,16 +171,14 @@ fn parse_name_directive(line: ~str, directive: ~str) -> bool {
fn parse_name_value_directive(line: ~str,
directive: ~str) -> Option<~str> {
unsafe {
let keycolon = directive + ~":";
match str::find_str(line, keycolon) {
Some(colon) => {
let value = str::slice(line, colon + str::len(keycolon),
str::len(line)).to_owned();
debug!("%s: %s", directive, value);
Some(value)
}
None => None
let keycolon = directive + ~":";
match str::find_str(line, keycolon) {
Some(colon) => {
let value = str::slice(line, colon + str::len(keycolon),
str::len(line)).to_owned();
debug!("%s: %s", directive, value);
Some(value)
}
None => None
}
}

View File

@ -188,16 +188,14 @@ impl<T: Owned> Peekable<T> for Port<T> {
#[inline(always)]
fn port_peek<T:Owned>(self: &Port<T>) -> bool {
unsafe {
let mut endp = None;
endp <-> self.endp;
let peek = match &endp {
&Some(ref endp) => peek(endp),
&None => fail!(~"peeking empty stream")
};
self.endp <-> endp;
peek
}
let mut endp = None;
endp <-> self.endp;
let peek = match &endp {
&Some(ref endp) => peek(endp),
&None => fail!(~"peeking empty stream")
};
self.endp <-> endp;
peek
}
impl<T: Owned> Selectable for Port<T> {

View File

@ -1536,11 +1536,8 @@ pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] {
pub fn with_str_writer(f: &fn(@Writer)) -> ~str {
let mut v = with_bytes_writer(f);
// FIXME (#3758): This should not be needed.
unsafe {
// Make sure the vector has a trailing null and is proper utf8.
v.push(0);
}
// Make sure the vector has a trailing null and is proper utf8.
v.push(0);
assert!(str::is_utf8(v));
unsafe { ::cast::transmute(v) }
@ -1640,16 +1637,14 @@ pub mod fsync {
// outer res
pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
blk: &fn(v: Res<*libc::FILE>)) {
unsafe {
blk(Res(Arg {
val: file.f, opt_level: opt_level,
fsync_fn: |file, l| {
unsafe {
os::fsync_fd(libc::fileno(file), l) as int
}
blk(Res(Arg {
val: file.f, opt_level: opt_level,
fsync_fn: |file, l| {
unsafe {
os::fsync_fd(libc::fileno(file), l) as int
}
}));
}
}
}));
}
// fsync fd after executing blk

View File

@ -38,13 +38,13 @@ pub mod raw {
#[inline(always)]
pub fn ptr_eq<T>(a: @T, b: @T) -> bool {
//! Determine if two shared boxes point to the same object
unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) }
ptr::addr_of(&(*a)) == ptr::addr_of(&(*b))
}
#[inline(always)]
pub fn mut_ptr_eq<T>(a: @mut T, b: @mut T) -> bool {
//! Determine if two mutable shared boxes point to the same object
unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) }
ptr::addr_of(&(*a)) == ptr::addr_of(&(*b))
}
#[cfg(notest)]

View File

@ -369,27 +369,27 @@ pub fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
#[inline(always)]
pub fn abs(x: float) -> float {
unsafe { f64::abs(x as f64) as float }
f64::abs(x as f64) as float
}
#[inline(always)]
pub fn sqrt(x: float) -> float {
unsafe { f64::sqrt(x as f64) as float }
f64::sqrt(x as f64) as float
}
#[inline(always)]
pub fn atan(x: float) -> float {
unsafe { f64::atan(x as f64) as float }
f64::atan(x as f64) as float
}
#[inline(always)]
pub fn sin(x: float) -> float {
unsafe { f64::sin(x as f64) as float }
f64::sin(x as f64) as float
}
#[inline(always)]
pub fn cos(x: float) -> float {
unsafe { f64::cos(x as f64) as float }
f64::cos(x as f64) as float
}
#[inline(always)]
pub fn tan(x: float) -> float {
unsafe { f64::tan(x as f64) as float }
f64::tan(x as f64) as float
}
#[cfg(notest)]

View File

@ -389,13 +389,11 @@ impl GenericPath for PosixPath {
}
fn dirname(&self) -> ~str {
unsafe {
let s = self.dir_path().to_str();
if s.len() == 0 {
~"."
} else {
s
}
let s = self.dir_path().to_str();
if s.len() == 0 {
~"."
} else {
s
}
}
@ -439,10 +437,8 @@ impl GenericPath for PosixPath {
}
fn with_filename(&self, f: &str) -> PosixPath {
unsafe {
assert!(! str::any(f, |c| windows::is_sep(c as u8)));
self.dir_path().push(f)
}
assert!(! str::any(f, |c| windows::is_sep(c as u8)));
self.dir_path().push(f)
}
fn with_filestem(&self, s: &str) -> PosixPath {
@ -509,7 +505,7 @@ impl GenericPath for PosixPath {
for str::each_split_nonempty(*e, |c| windows::is_sep(c as u8)) |s| {
ss.push(s.to_owned())
}
unsafe { v.push_all_move(ss); }
v.push_all_move(ss);
}
PosixPath { is_absolute: self.is_absolute,
components: v }
@ -521,14 +517,14 @@ impl GenericPath for PosixPath {
for str::each_split_nonempty(s, |c| windows::is_sep(c as u8)) |s| {
ss.push(s.to_owned())
}
unsafe { v.push_all_move(ss); }
v.push_all_move(ss);
PosixPath { components: v, ..copy *self }
}
fn pop(&self) -> PosixPath {
let mut cs = copy self.components;
if cs.len() != 0 {
unsafe { cs.pop(); }
cs.pop();
}
return PosixPath {
is_absolute: self.is_absolute,
@ -607,13 +603,11 @@ impl GenericPath for WindowsPath {
}
fn dirname(&self) -> ~str {
unsafe {
let s = self.dir_path().to_str();
if s.len() == 0 {
~"."
} else {
s
}
let s = self.dir_path().to_str();
if s.len() == 0 {
~"."
} else {
s
}
}
@ -770,7 +764,7 @@ impl GenericPath for WindowsPath {
for str::each_split_nonempty(*e, |c| windows::is_sep(c as u8)) |s| {
ss.push(s.to_owned())
}
unsafe { v.push_all_move(ss); }
v.push_all_move(ss);
}
// tedious, but as-is, we can't use ..self
return WindowsPath {
@ -787,14 +781,14 @@ impl GenericPath for WindowsPath {
for str::each_split_nonempty(s, |c| windows::is_sep(c as u8)) |s| {
ss.push(s.to_owned())
}
unsafe { v.push_all_move(ss); }
v.push_all_move(ss);
return WindowsPath { components: v, ..copy *self }
}
fn pop(&self) -> WindowsPath {
let mut cs = copy self.components;
if cs.len() != 0 {
unsafe { cs.pop(); }
cs.pop();
}
return WindowsPath {
host: copy self.host,
@ -820,18 +814,14 @@ impl GenericPath for WindowsPath {
pub fn normalize(components: &[~str]) -> ~[~str] {
let mut cs = ~[];
unsafe {
for components.each |c| {
unsafe {
if *c == ~"." && components.len() > 1 { loop; }
if *c == ~"" { loop; }
if *c == ~".." && cs.len() != 0 {
cs.pop();
loop;
}
cs.push(copy *c);
}
for components.each |c| {
if *c == ~"." && components.len() > 1 { loop; }
if *c == ~"" { loop; }
if *c == ~".." && cs.len() != 0 {
cs.pop();
loop;
}
cs.push(copy *c);
}
cs
}

View File

@ -55,17 +55,13 @@ pub fn addr_of<T>(val: &T) -> *T { unsafe { rusti::addr_of(*val) } }
/// Calculate the offset from a pointer
#[inline(always)]
pub fn offset<T>(ptr: *T, count: uint) -> *T {
unsafe {
(ptr as uint + count * sys::size_of::<T>()) as *T
}
(ptr as uint + count * sys::size_of::<T>()) as *T
}
/// Calculate the offset from a const pointer
#[inline(always)]
pub fn const_offset<T>(ptr: *const T, count: uint) -> *const T {
unsafe {
(ptr as uint + count * sys::size_of::<T>()) as *T
}
(ptr as uint + count * sys::size_of::<T>()) as *T
}
/// Calculate the offset from a mut pointer

View File

@ -205,8 +205,6 @@ fn align_down(sp: *mut uint) -> *mut uint {
#[inline(always)]
pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
use core::sys::size_of;
unsafe {
(ptr as int + count * (size_of::<T>() as int)) as *mut T
}
(ptr as int + count * (size_of::<T>() as int)) as *mut T
}

View File

@ -21,17 +21,17 @@ pub type Key = pthread_key_t;
#[cfg(unix)]
pub unsafe fn create(key: &mut Key) {
unsafe { assert!(0 == pthread_key_create(key, null())); }
assert!(0 == pthread_key_create(key, null()));
}
#[cfg(unix)]
pub unsafe fn set(key: Key, value: *mut c_void) {
unsafe { assert!(0 == pthread_setspecific(key, value)); }
assert!(0 == pthread_setspecific(key, value));
}
#[cfg(unix)]
pub unsafe fn get(key: Key) -> *mut c_void {
unsafe { pthread_getspecific(key) }
pthread_getspecific(key)
}
#[cfg(target_os="macos")]

View File

@ -382,64 +382,62 @@ pub struct ProgramOutput {status: int, out: ~str, err: ~str}
* the contents of stdout and the contents of stderr.
*/
pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
unsafe {
let pipe_in = os::pipe();
let pipe_out = os::pipe();
let pipe_err = os::pipe();
let pid = spawn_process(prog, args, &None, &None,
pipe_in.in, pipe_out.out, pipe_err.out);
os::close(pipe_in.in);
os::close(pipe_out.out);
os::close(pipe_err.out);
if pid == -1i32 {
os::close(pipe_in.out);
os::close(pipe_out.in);
os::close(pipe_err.in);
fail!();
}
let pipe_in = os::pipe();
let pipe_out = os::pipe();
let pipe_err = os::pipe();
let pid = spawn_process(prog, args, &None, &None,
pipe_in.in, pipe_out.out, pipe_err.out);
os::close(pipe_in.in);
os::close(pipe_out.out);
os::close(pipe_err.out);
if pid == -1i32 {
os::close(pipe_in.out);
// Spawn two entire schedulers to read both stdout and sterr
// in parallel so we don't deadlock while blocking on one
// or the other. FIXME (#2625): Surely there's a much more
// clever way to do this.
let (p, ch) = stream();
let ch = SharedChan(ch);
let ch_clone = ch.clone();
do task::spawn_sched(task::SingleThreaded) {
let errput = readclose(pipe_err.in);
ch.send((2, errput));
};
do task::spawn_sched(task::SingleThreaded) {
let output = readclose(pipe_out.in);
ch_clone.send((1, output));
};
let status = run::waitpid(pid);
let mut errs = ~"";
let mut outs = ~"";
let mut count = 2;
while count > 0 {
let stream = p.recv();
match stream {
(1, copy s) => {
outs = s;
}
(2, copy s) => {
errs = s;
}
(n, _) => {
fail!(fmt!("program_output received an unexpected file \
number: %u", n));
}
};
count -= 1;
};
return ProgramOutput {status: status,
out: outs,
err: errs};
os::close(pipe_out.in);
os::close(pipe_err.in);
fail!();
}
os::close(pipe_in.out);
// Spawn two entire schedulers to read both stdout and sterr
// in parallel so we don't deadlock while blocking on one
// or the other. FIXME (#2625): Surely there's a much more
// clever way to do this.
let (p, ch) = stream();
let ch = SharedChan(ch);
let ch_clone = ch.clone();
do task::spawn_sched(task::SingleThreaded) {
let errput = readclose(pipe_err.in);
ch.send((2, errput));
};
do task::spawn_sched(task::SingleThreaded) {
let output = readclose(pipe_out.in);
ch_clone.send((1, output));
};
let status = run::waitpid(pid);
let mut errs = ~"";
let mut outs = ~"";
let mut count = 2;
while count > 0 {
let stream = p.recv();
match stream {
(1, copy s) => {
outs = s;
}
(2, copy s) => {
errs = s;
}
(n, _) => {
fail!(fmt!("program_output received an unexpected file \
number: %u", n));
}
};
count -= 1;
};
return ProgramOutput {status: status,
out: outs,
err: errs};
}
pub fn writeclose(fd: c_int, s: ~str) {

View File

@ -170,18 +170,16 @@ pub fn push_char(s: &mut ~str, ch: char) {
/// Convert a char to a string
pub fn from_char(ch: char) -> ~str {
let mut buf = ~"";
unsafe { push_char(&mut buf, ch); }
push_char(&mut buf, ch);
buf
}
/// Convert a vector of chars to a string
pub fn from_chars(chs: &[char]) -> ~str {
let mut buf = ~"";
unsafe {
reserve(&mut buf, chs.len());
for vec::each(chs) |ch| {
push_char(&mut buf, *ch);
}
reserve(&mut buf, chs.len());
for vec::each(chs) |ch| {
push_char(&mut buf, *ch);
}
buf
}
@ -226,9 +224,7 @@ pub fn push_str(lhs: &mut ~str, rhs: &str) {
#[inline(always)]
pub fn append(lhs: ~str, rhs: &str) -> ~str {
let mut v = lhs;
unsafe {
push_str_no_overallocate(&mut v, rhs);
}
push_str_no_overallocate(&mut v, rhs);
v
}
@ -236,7 +232,7 @@ pub fn append(lhs: ~str, rhs: &str) -> ~str {
pub fn concat(v: &[~str]) -> ~str {
let mut s: ~str = ~"";
for vec::each(v) |ss| {
unsafe { push_str(&mut s, *ss) };
push_str(&mut s, *ss);
}
s
}
@ -245,8 +241,8 @@ pub fn concat(v: &[~str]) -> ~str {
pub fn connect(v: &[~str], sep: &str) -> ~str {
let mut s = ~"", first = true;
for vec::each(v) |ss| {
if first { first = false; } else { unsafe { push_str(&mut s, sep); } }
unsafe { push_str(&mut s, *ss) };
if first { first = false; } else { push_str(&mut s, sep); }
push_str(&mut s, *ss);
}
s
}
@ -255,8 +251,8 @@ pub fn connect(v: &[~str], sep: &str) -> ~str {
pub fn connect_slices(v: &[&str], sep: &str) -> ~str {
let mut s = ~"", first = true;
for vec::each(v) |ss| {
if first { first = false; } else { unsafe { push_str(&mut s, sep); } }
unsafe { push_str(&mut s, *ss) };
if first { first = false; } else { push_str(&mut s, sep); }
push_str(&mut s, *ss);
}
s
}
@ -2251,16 +2247,14 @@ pub mod raw {
assert!((end <= n));
let mut v = vec::with_capacity(end - begin + 1u);
unsafe {
do vec::as_imm_buf(v) |vbuf, _vlen| {
let vbuf = ::cast::transmute_mut_unsafe(vbuf);
let src = ptr::offset(sbuf, begin);
ptr::copy_memory(vbuf, src, end - begin);
}
vec::raw::set_len(&mut v, end - begin);
v.push(0u8);
::cast::transmute(v)
do vec::as_imm_buf(v) |vbuf, _vlen| {
let vbuf = ::cast::transmute_mut_unsafe(vbuf);
let src = ptr::offset(sbuf, begin);
ptr::copy_memory(vbuf, src, end - begin);
}
vec::raw::set_len(&mut v, end - begin);
v.push(0u8);
::cast::transmute(v)
}
}
@ -2304,7 +2298,7 @@ pub mod raw {
}
/// Removes the last byte from a string and returns it. (Not UTF-8 safe).
pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
pub fn pop_byte(s: &mut ~str) -> u8 {
let len = len(*s);
assert!((len > 0u));
let b = s[len - 1u];
@ -2313,7 +2307,7 @@ pub mod raw {
}
/// Removes the first byte from a string and returns it. (Not UTF-8 safe).
pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
pub fn shift_byte(s: &mut ~str) -> u8 {
let len = len(*s);
assert!((len > 0u));
let b = s[0];

View File

@ -127,10 +127,8 @@ pub fn refcount<T>(t: @T) -> uint {
}
pub fn log_str<T>(t: &T) -> ~str {
unsafe {
do io::with_str_writer |wr| {
repr::write_repr(wr, t)
}
do io::with_str_writer |wr| {
repr::write_repr(wr, t)
}
}
@ -157,10 +155,8 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
}
pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! {
unsafe {
let (msg, file) = (msg.to_owned(), file.to_owned());
begin_unwind(~"assertion failed: " + msg, file, line)
}
let (msg, file) = (msg.to_owned(), file.to_owned());
begin_unwind(~"assertion failed: " + msg, file, line)
}
#[cfg(test)]

View File

@ -39,10 +39,9 @@ use result::Result;
use comm::{stream, Chan, GenericChan, GenericPort, Port};
use prelude::*;
use result;
use task::rt::{task_id, sched_id};
use task::rt::{task_id, sched_id, rust_task};
use util;
use util::replace;
use unstable::finally::Finally;
#[cfg(test)] use comm::SharedChan;
@ -566,28 +565,48 @@ pub fn get_scheduler() -> Scheduler {
* ~~~
*/
pub unsafe fn unkillable<U>(f: &fn() -> U) -> U {
unsafe {
let t = rt::rust_get_task();
rt::rust_task_inhibit_kill(t);
do (|| {
f()
}).finally {
rt::rust_task_allow_kill(t);
struct AllowFailure {
t: *rust_task,
drop {
unsafe {
rt::rust_task_allow_kill(self.t);
}
}
}
fn AllowFailure(t: *rust_task) -> AllowFailure{
AllowFailure {
t: t
}
}
let t = rt::rust_get_task();
let _allow_failure = AllowFailure(t);
rt::rust_task_inhibit_kill(t);
f()
}
/// The inverse of unkillable. Only ever to be used nested in unkillable().
pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
unsafe {
let t = rt::rust_get_task();
rt::rust_task_allow_kill(t);
do (|| {
f()
}).finally {
rt::rust_task_inhibit_kill(t);
struct DisallowFailure {
t: *rust_task,
drop {
unsafe {
rt::rust_task_inhibit_kill(self.t);
}
}
}
fn DisallowFailure(t: *rust_task) -> DisallowFailure {
DisallowFailure {
t: t
}
}
let t = rt::rust_get_task();
let _allow_failure = DisallowFailure(t);
rt::rust_task_allow_kill(t);
f()
}
/**
@ -595,17 +614,27 @@ pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
* For use with exclusive ARCs, which use pthread mutexes directly.
*/
pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
unsafe {
let t = rt::rust_get_task();
rt::rust_task_inhibit_kill(t);
rt::rust_task_inhibit_yield(t);
do (|| {
f()
}).finally {
rt::rust_task_allow_yield(t);
rt::rust_task_allow_kill(t);
struct DeferInterrupts {
t: *rust_task,
drop {
unsafe {
rt::rust_task_allow_yield(self.t);
rt::rust_task_allow_kill(self.t);
}
}
}
fn DeferInterrupts(t: *rust_task) -> DeferInterrupts {
DeferInterrupts {
t: t
}
}
let t = rt::rust_get_task();
let _interrupts = DeferInterrupts(t);
rt::rust_task_inhibit_kill(t);
rt::rust_task_inhibit_yield(t);
f()
}
#[test] #[should_fail] #[ignore(cfg(windows))]

View File

@ -157,13 +157,13 @@ struct AncestorList(Option<unstable::Exclusive<AncestorNode>>);
// Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety.
#[inline(always)]
fn access_group<U>(x: &TaskGroupArc, blk: &fn(TaskGroupInner) -> U) -> U {
unsafe { x.with(blk) }
x.with(blk)
}
#[inline(always)]
fn access_ancestors<U>(x: &unstable::Exclusive<AncestorNode>,
blk: &fn(x: &mut AncestorNode) -> U) -> U {
unsafe { x.with(blk) }
x.with(blk)
}
// Iterates over an ancestor list.

View File

@ -152,45 +152,37 @@ pub type SharedMutableState<T> = ArcDestruct<T>;
pub unsafe fn shared_mutable_state<T:Owned>(data: T) ->
SharedMutableState<T> {
let data = ~ArcData { count: 1, data: Some(data) };
unsafe {
let ptr = cast::transmute(data);
ArcDestruct(ptr)
}
let ptr = cast::transmute(data);
ArcDestruct(ptr)
}
#[inline(always)]
pub unsafe fn get_shared_mutable_state<T:Owned>(
rc: *SharedMutableState<T>) -> *mut T
{
unsafe {
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
assert!(ptr.count > 0);
let r = cast::transmute(ptr.data.get_ref());
cast::forget(ptr);
return r;
}
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
assert!(ptr.count > 0);
let r = cast::transmute(ptr.data.get_ref());
cast::forget(ptr);
return r;
}
#[inline(always)]
pub unsafe fn get_shared_immutable_state<'a,T:Owned>(
rc: &'a SharedMutableState<T>) -> &'a T {
unsafe {
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
assert!(ptr.count > 0);
// Cast us back into the correct region
let r = cast::transmute_region(ptr.data.get_ref());
cast::forget(ptr);
return r;
}
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
assert!(ptr.count > 0);
// Cast us back into the correct region
let r = cast::transmute_region(ptr.data.get_ref());
cast::forget(ptr);
return r;
}
pub unsafe fn clone_shared_mutable_state<T:Owned>(rc: &SharedMutableState<T>)
-> SharedMutableState<T> {
unsafe {
let mut ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1;
assert!(new_count >= 2);
cast::forget(ptr);
}
let mut ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1;
assert!(new_count >= 2);
cast::forget(ptr);
ArcDestruct((*rc).data)
}

View File

@ -19,27 +19,25 @@ use ptr::null;
use intrinsic::TyDesc;
pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void {
unsafe {
assert!(td.is_not_null());
assert!(td.is_not_null());
let total_size = get_box_size(size, (*td).align);
let p = c_malloc(total_size as size_t);
assert!(p.is_not_null());
let total_size = get_box_size(size, (*td).align);
let p = c_malloc(total_size as size_t);
assert!(p.is_not_null());
// FIXME #3475: Converting between our two different tydesc types
let td: *TyDesc = transmute(td);
// FIXME #3475: Converting between our two different tydesc types
let td: *TyDesc = transmute(td);
let box: &mut BoxRepr = transmute(p);
box.header.ref_count = -1; // Exchange values not ref counted
box.header.type_desc = td;
box.header.prev = null();
box.header.next = null();
let box: &mut BoxRepr = transmute(p);
box.header.ref_count = -1; // Exchange values not ref counted
box.header.type_desc = td;
box.header.prev = null();
box.header.next = null();
let exchange_count = &mut *rust_get_exchange_count_ptr();
atomic_xadd(exchange_count, 1);
let exchange_count = &mut *rust_get_exchange_count_ptr();
atomic_xadd(exchange_count, 1);
return transmute(box);
}
return transmute(box);
}
/**
Thin wrapper around libc::malloc, none of the box header

View File

@ -512,7 +512,7 @@ pub mod rt {
None
}
} else { Some('-') };
unsafe { pad(cv, s, head, PadSigned, buf) };
pad(cv, s, head, PadSigned, buf);
}
pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) {
let prec = get_int_precision(cv);
@ -524,7 +524,7 @@ pub mod rt {
TyBits => uint_to_str_prec(u, 2, prec),
TyOctal => uint_to_str_prec(u, 8, prec)
};
unsafe { pad(cv, rs, None, PadUnsigned, buf) };
pad(cv, rs, None, PadUnsigned, buf);
}
pub fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) {
let s = if b { "true" } else { "false" };
@ -533,7 +533,7 @@ pub mod rt {
conv_str(cv, s, buf);
}
pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) {
unsafe { pad(cv, "", Some(c), PadNozero, buf) };
pad(cv, "", Some(c), PadNozero, buf);
}
pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
// For strings, precision is the maximum characters
@ -546,14 +546,14 @@ pub mod rt {
s
}
};
unsafe { pad(cv, unpadded, None, PadNozero, buf) };
pad(cv, unpadded, None, PadNozero, buf);
}
pub fn conv_float(cv: Conv, f: float, buf: &mut ~str) {
let (to_str, digits) = match cv.precision {
CountIs(c) => (float::to_str_exact, c as uint),
CountImplied => (float::to_str_digits, 6u)
};
let mut s = unsafe { to_str(f, digits) };
let mut s = to_str(f, digits);
let head = if 0.0 <= f {
if have_flag(cv.flags, flag_sign_always) {
Some('+')
@ -563,7 +563,7 @@ pub mod rt {
None
}
} else { None };
unsafe { pad(cv, s, head, PadFloat, buf) };
pad(cv, s, head, PadFloat, buf);
}
pub fn conv_poly<T>(cv: Conv, v: &T, buf: &mut ~str) {
let s = sys::log_str(v);

View File

@ -44,7 +44,7 @@ pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! {
}
#[lang="fail_bounds_check"]
pub unsafe fn fail_bounds_check(file: *c_char, line: size_t,
pub fn fail_bounds_check(file: *c_char, line: size_t,
index: size_t, len: size_t) {
let msg = fmt!("index out of bounds: the len is %d but the index is %d",
len as int, index as int);
@ -53,7 +53,7 @@ pub unsafe fn fail_bounds_check(file: *c_char, line: size_t,
}
}
pub unsafe fn fail_borrowed() {
pub fn fail_borrowed() {
let msg = "borrowed";
do str::as_buf(msg) |msg_p, _| {
do str::as_buf("???") |file_p, _| {

View File

@ -615,9 +615,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
}
pub fn truncated_hash_result(symbol_hasher: &hash::State) -> ~str {
unsafe {
symbol_hasher.result_str()
}
symbol_hasher.result_str()
}

View File

@ -33,6 +33,7 @@ use util::ppaux::ty_to_str;
use core::hashmap::HashSet;
use core::uint;
use core::util::with;
use syntax::ast::m_mutbl;
use syntax::ast;
use syntax::ast_util;
@ -40,13 +41,18 @@ use syntax::codemap::span;
use syntax::print::pprust;
use syntax::visit;
struct PurityState {
def: ast::node_id,
purity: ast::purity
}
struct CheckLoanCtxt {
bccx: @BorrowckCtxt,
req_maps: ReqMaps,
reported: HashSet<ast::node_id>,
declared_purity: @mut ast::purity,
declared_purity: @mut PurityState,
fn_args: @mut @~[ast::node_id]
}
@ -62,6 +68,16 @@ enum purity_cause {
pc_cmt(bckerr)
}
// if we're not pure, why?
#[deriving(Eq)]
enum impurity_cause {
// some surrounding block was marked as 'unsafe'
pc_unsafe,
// nothing was unsafe, and nothing was pure
pc_default,
}
pub fn check_loans(bccx: @BorrowckCtxt,
+req_maps: ReqMaps,
crate: @ast::crate) {
@ -69,7 +85,8 @@ pub fn check_loans(bccx: @BorrowckCtxt,
bccx: bccx,
req_maps: req_maps,
reported: HashSet::new(),
declared_purity: @mut ast::impure_fn,
declared_purity: @mut PurityState { purity: ast::impure_fn,
def: 0 },
fn_args: @mut @~[]
};
let vt = visit::mk_vt(@visit::Visitor {visit_expr: check_loans_in_expr,
@ -106,16 +123,18 @@ pub impl assignment_type {
pub impl CheckLoanCtxt {
fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
fn purity(&mut self, scope_id: ast::node_id) -> Option<purity_cause> {
let default_purity = match *self.declared_purity {
fn purity(&mut self, scope_id: ast::node_id)
-> Either<purity_cause, impurity_cause>
{
let default_purity = match self.declared_purity.purity {
// an unsafe declaration overrides all
ast::unsafe_fn => return None,
ast::unsafe_fn => return Right(pc_unsafe),
// otherwise, remember what was declared as the
// default, but we must scan for requirements
// imposed by the borrow check
ast::pure_fn => Some(pc_pure_fn),
ast::extern_fn | ast::impure_fn => None
ast::pure_fn => Left(pc_pure_fn),
ast::extern_fn | ast::impure_fn => Right(pc_default)
};
// scan to see if this scope or any enclosing scope requires
@ -125,7 +144,7 @@ pub impl CheckLoanCtxt {
loop {
match self.req_maps.pure_map.find(&scope_id) {
None => (),
Some(e) => return Some(pc_cmt(*e))
Some(e) => return Left(pc_cmt(*e))
}
match self.tcx().region_maps.opt_encl_scope(scope_id) {
@ -171,7 +190,7 @@ pub impl CheckLoanCtxt {
// overloaded operators the callee has an id but no expr.
// annoying.
fn check_pure_callee_or_arg(&mut self,
pc: purity_cause,
pc: Either<purity_cause, impurity_cause>,
opt_expr: Option<@ast::expr>,
callee_id: ast::node_id,
callee_span: span) {
@ -196,7 +215,7 @@ pub impl CheckLoanCtxt {
match opt_expr {
Some(expr) => {
match expr.node {
ast::expr_path(_) if pc == pc_pure_fn => {
ast::expr_path(_) if pc == Left(pc_pure_fn) => {
let def = *self.tcx().def_map.get(&expr.id);
let did = ast_util::def_id_of_def(def);
let is_fn_arg =
@ -361,10 +380,10 @@ pub impl CheckLoanCtxt {
// if this is a pure function, only loan-able state can be
// assigned, because it is uniquely tied to this function and
// is not visible from the outside
match self.purity(ex.id) {
None => (),
Some(pc_cmt(_)) => {
let purity = self.purity(ex.id).get();
let purity = self.purity(ex.id);
match purity {
Right(_) => (),
Left(pc_cmt(_)) => {
// Subtle: Issue #3162. If we are enforcing purity
// because there is a reference to aliasable, mutable data
// that we require to be immutable, we can't allow writes
@ -376,10 +395,10 @@ pub impl CheckLoanCtxt {
ex.span,
at.ing_form(self.bccx.cmt_to_str(cmt)));
}
Some(pc_pure_fn) => {
Left(pc_pure_fn) => {
if cmt.lp.is_none() {
self.report_purity_error(
pc_pure_fn, ex.span,
purity, ex.span,
at.ing_form(self.bccx.cmt_to_str(cmt)));
}
}
@ -462,14 +481,23 @@ pub impl CheckLoanCtxt {
}
}
fn report_purity_error(&mut self, pc: purity_cause, sp: span, msg: ~str) {
fn report_purity_error(&mut self, pc: Either<purity_cause, impurity_cause>,
sp: span, msg: ~str) {
match pc {
pc_pure_fn => {
Right(pc_default) => { fail!(~"pc_default should be filtered sooner") }
Right(pc_unsafe) => {
// this error was prevented by being marked as unsafe, so flag the
// definition as having contributed to the validity of the program
let def = self.declared_purity.def;
debug!("flagging %? as a used unsafe source", def);
self.tcx().used_unsafe.insert(def);
}
Left(pc_pure_fn) => {
self.tcx().sess.span_err(
sp,
fmt!("%s prohibited in pure context", msg));
}
pc_cmt(ref e) => {
Left(pc_cmt(ref e)) => {
if self.reported.insert((*e).cmt.id) {
self.tcx().sess.span_err(
(*e).cmt.span,
@ -556,16 +584,32 @@ pub impl CheckLoanCtxt {
callee_id: ast::node_id,
callee_span: span,
args: &[@ast::expr]) {
match self.purity(expr.id) {
None => {}
Some(ref pc) => {
self.check_pure_callee_or_arg(
(*pc), callee, callee_id, callee_span);
for args.each |arg| {
self.check_pure_callee_or_arg(
(*pc), Some(*arg), arg.id, arg.span);
let pc = self.purity(expr.id);
match pc {
// no purity, no need to check for anything
Right(pc_default) => return,
// some form of purity, definitely need to check
Left(_) => (),
// Unsafe trumped. To see if the unsafe is necessary, see what the
// purity would have been without a trump, and if it's some form
// of purity then we need to go ahead with the check
Right(pc_unsafe) => {
match do with(&mut self.declared_purity.purity,
ast::impure_fn) { self.purity(expr.id) } {
Right(pc_unsafe) => fail!(~"unsafe can't trump twice"),
Right(pc_default) => return,
Left(_) => ()
}
}
}
}
self.check_pure_callee_or_arg(
pc, callee, callee_id, callee_span);
for args.each |arg| {
self.check_pure_callee_or_arg(
pc, Some(*arg), arg.id, arg.span);
}
}
}
@ -580,27 +624,32 @@ fn check_loans_in_fn(fk: &visit::fn_kind,
let is_stack_closure = self.is_stack_closure(id);
let fty = ty::node_id_to_type(self.tcx(), id);
let declared_purity;
let declared_purity, src;
match *fk {
visit::fk_item_fn(*) | visit::fk_method(*) |
visit::fk_dtor(*) => {
declared_purity = ty::ty_fn_purity(fty);
src = id;
}
visit::fk_anon(*) | visit::fk_fn_block(*) => {
let fty_sigil = ty::ty_closure_sigil(fty);
check_moves_from_captured_variables(self, id, fty_sigil);
declared_purity = ty::determine_inherited_purity(
*self.declared_purity,
ty::ty_fn_purity(fty),
let pair = ty::determine_inherited_purity(
(self.declared_purity.purity, self.declared_purity.def),
(ty::ty_fn_purity(fty), id),
fty_sigil);
declared_purity = pair.first();
src = pair.second();
}
}
debug!("purity on entry=%?", copy self.declared_purity);
do save_and_restore_managed(self.declared_purity) {
do save_and_restore_managed(self.fn_args) {
*self.declared_purity = declared_purity;
self.declared_purity = @mut PurityState {
purity: declared_purity, def: src
};
match *fk {
visit::fk_anon(*) |
@ -754,7 +803,10 @@ fn check_loans_in_block(blk: &ast::blk,
ast::default_blk => {
}
ast::unsafe_blk => {
*self.declared_purity = ast::unsafe_fn;
*self.declared_purity = PurityState {
purity: ast::unsafe_fn,
def: blk.node.id,
};
}
}

View File

@ -369,7 +369,7 @@ pub impl<'self> LanguageItemCollector<'self> {
}
fn collect_local_language_items(&self) {
let this = unsafe { ptr::addr_of(&self) };
let this = ptr::addr_of(&self);
visit_crate(*self.crate, (), mk_simple_visitor(@SimpleVisitor {
visit_item: |item| {
for item.attrs.each |attribute| {

View File

@ -75,6 +75,7 @@ pub enum lint {
default_methods,
deprecated_mutable_fields,
deprecated_drop,
unused_unsafe,
foreign_mode,
managed_heap_memory,
@ -256,6 +257,13 @@ pub fn get_lint_dict() -> LintDict {
default: deny
}),
(~"unused_unsafe",
LintSpec {
lint: unused_unsafe,
desc: "unnecessary use of an \"unsafe\" block or function",
default: warn
}),
(~"unused_variable",
LintSpec {
lint: unused_variable,
@ -490,6 +498,7 @@ fn check_item(i: @ast::item, cx: ty::ctxt) {
check_item_default_methods(cx, i);
check_item_deprecated_mutable_fields(cx, i);
check_item_deprecated_drop(cx, i);
check_item_unused_unsafe(cx, i);
}
// Take a visitor, and modify it so that it will not proceed past subitems.
@ -923,19 +932,55 @@ fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) {
}
}
fn check_item_unused_unsafe(cx: ty::ctxt, it: @ast::item) {
let visit_expr: @fn(@ast::expr) = |e| {
match e.node {
ast::expr_block(ref blk) if blk.node.rules == ast::unsafe_blk => {
if !cx.used_unsafe.contains(&blk.node.id) {
cx.sess.span_lint(unused_unsafe, blk.node.id, it.id,
blk.span,
~"unnecessary \"unsafe\" block");
}
}
_ => ()
}
};
let visit = item_stopping_visitor(
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr: visit_expr,
.. *visit::default_simple_visitor()
}));
visit::visit_item(it, (), visit);
}
fn check_fn(tcx: ty::ctxt, fk: &visit::fn_kind, decl: &ast::fn_decl,
_body: &ast::blk, span: span, id: ast::node_id) {
debug!("lint check_fn fk=%? id=%?", fk, id);
// don't complain about blocks, since they tend to get their modes
// specified from the outside
// Check for an 'unsafe fn' which doesn't need to be unsafe
match *fk {
visit::fk_fn_block(*) => { return; }
_ => {}
visit::fk_item_fn(_, _, ast::unsafe_fn, _) => {
if !tcx.used_unsafe.contains(&id) {
tcx.sess.span_lint(unused_unsafe, id, id, span,
~"unnecessary \"unsafe\" function");
}
}
_ => ()
}
// Check for deprecated modes
match *fk {
// don't complain about blocks, since they tend to get their modes
// specified from the outside
visit::fk_fn_block(*) => {}
_ => {
let fn_ty = ty::node_id_to_type(tcx, id);
check_fn_deprecated_modes(tcx, fn_ty, decl, span, id);
}
}
let fn_ty = ty::node_id_to_type(tcx, id);
check_fn_deprecated_modes(tcx, fn_ty, decl, span, id);
}
fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: &ast::fn_decl,

View File

@ -19,7 +19,7 @@ use metadata::csearch::get_type_name_if_impl;
use metadata::cstore::find_extern_mod_stmt_cnum;
use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
use middle::lang_items::LanguageItems;
use middle::lint::{deny, allow, forbid, level, unused_imports, warn};
use middle::lint::{allow, level, unused_imports};
use middle::lint::{get_lint_level, get_lint_settings_level};
use middle::pat_util::pat_bindings;
@ -5212,17 +5212,11 @@ pub impl Resolver {
import_resolution.span != dummy_sp() &&
import_resolution.privacy != Public {
import_resolution.state.warned = true;
match self.unused_import_lint_level(module_) {
warn => {
self.session.span_warn(copy import_resolution.span,
~"unused import");
}
deny | forbid => {
self.session.span_err(copy import_resolution.span,
~"unused import");
}
allow => ()
}
let span = import_resolution.span;
self.session.span_lint_level(
self.unused_import_lint_level(module_),
span,
~"unused import");
}
}
}

View File

@ -91,10 +91,8 @@ pub struct icx_popper {
#[unsafe_destructor]
impl Drop for icx_popper {
fn finalize(&self) {
unsafe {
if self.ccx.sess.count_llvm_insns() {
self.ccx.stats.llvm_insn_ctxt.pop();
}
if self.ccx.sess.count_llvm_insns() {
self.ccx.stats.llvm_insn_ctxt.pop();
}
}
}
@ -145,9 +143,7 @@ pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
llvm::LLVMGetOrInsertFunction(llmod, buf, llty)
}
});
unsafe {
lib::llvm::SetFunctionCallConv(llfn, cc);
}
lib::llvm::SetFunctionCallConv(llfn, cc);
return llfn;
}
@ -730,11 +726,9 @@ pub fn cast_shift_expr_rhs(cx: block, op: ast::binop,
pub fn cast_shift_const_rhs(op: ast::binop,
lhs: ValueRef, rhs: ValueRef) -> ValueRef {
unsafe {
cast_shift_rhs(op, lhs, rhs,
|a, b| unsafe { llvm::LLVMConstTrunc(a, b) },
|a, b| unsafe { llvm::LLVMConstZExt(a, b) })
}
cast_shift_rhs(op, lhs, rhs,
|a, b| unsafe { llvm::LLVMConstTrunc(a, b) },
|a, b| unsafe { llvm::LLVMConstZExt(a, b) })
}
pub fn cast_shift_rhs(op: ast::binop,
@ -2865,9 +2859,7 @@ pub fn create_module_map(ccx: @CrateContext) -> ValueRef {
llvm::LLVMAddGlobal(ccx.llmod, maptype, buf)
}
});
unsafe {
lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage);
}
lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage);
let mut elts: ~[ValueRef] = ~[];
for ccx.module_data.each |key, &val| {
let elt = C_struct(~[p2i(ccx, C_cstr(ccx, @/*bad*/ copy *key)),

View File

@ -27,9 +27,7 @@ use core::str;
use core::vec;
pub fn terminate(cx: block, _: &str) {
unsafe {
cx.terminated = true;
}
cx.terminated = true;
}
pub fn check_not_terminated(cx: block) {

View File

@ -172,17 +172,15 @@ fn cast_safely<T:Copy,U>(val: T) -> U {
}
fn md_from_metadata<T>(val: debug_metadata) -> T {
unsafe {
match val {
file_metadata(md) => cast_safely(md),
compile_unit_metadata(md) => cast_safely(md),
subprogram_metadata(md) => cast_safely(md),
local_var_metadata(md) => cast_safely(md),
tydesc_metadata(md) => cast_safely(md),
block_metadata(md) => cast_safely(md),
argument_metadata(md) => cast_safely(md),
retval_metadata(md) => cast_safely(md)
}
match val {
file_metadata(md) => cast_safely(md),
compile_unit_metadata(md) => cast_safely(md),
subprogram_metadata(md) => cast_safely(md),
local_var_metadata(md) => cast_safely(md),
tydesc_metadata(md) => cast_safely(md),
block_metadata(md) => cast_safely(md),
argument_metadata(md) => cast_safely(md),
retval_metadata(md) => cast_safely(md)
}
}
@ -190,56 +188,52 @@ fn cached_metadata<T:Copy>(cache: metadata_cache,
mdtag: int,
eq_fn: &fn(md: T) -> bool)
-> Option<T> {
unsafe {
if cache.contains_key(&mdtag) {
let items = cache.get(&mdtag);
for items.each |item| {
let md: T = md_from_metadata::<T>(*item);
if eq_fn(md) {
return option::Some(md);
}
if cache.contains_key(&mdtag) {
let items = cache.get(&mdtag);
for items.each |item| {
let md: T = md_from_metadata::<T>(*item);
if eq_fn(md) {
return option::Some(md);
}
}
return option::None;
}
return option::None;
}
fn create_compile_unit(cx: @CrateContext) -> @Metadata<CompileUnitMetadata> {
unsafe {
let cache = get_cache(cx);
let crate_name = /*bad*/copy (/*bad*/copy cx.dbg_cx).get().crate_file;
let tg = CompileUnitTag;
match cached_metadata::<@Metadata<CompileUnitMetadata>>(cache, tg,
|md| md.data.name == crate_name) {
option::Some(md) => return md,
option::None => ()
}
let (_, work_dir) = get_file_path_and_dir(
cx.sess.working_dir.to_str(), crate_name);
let unit_metadata = ~[lltag(tg),
llunused(),
lli32(DW_LANG_RUST),
llstr(crate_name),
llstr(work_dir),
llstr(env!("CFG_VERSION")),
lli1(true), // deprecated: main compile unit
lli1(cx.sess.opts.optimize != session::No),
llstr(~""), // flags (???)
lli32(0) // runtime version (???)
];
let unit_node = llmdnode(unit_metadata);
add_named_metadata(cx, ~"llvm.dbg.cu", unit_node);
let mdval = @Metadata {
node: unit_node,
data: CompileUnitMetadata {
name: crate_name
}
};
update_cache(cache, tg, compile_unit_metadata(mdval));
return mdval;
let cache = get_cache(cx);
let crate_name = /*bad*/copy (/*bad*/copy cx.dbg_cx).get().crate_file;
let tg = CompileUnitTag;
match cached_metadata::<@Metadata<CompileUnitMetadata>>(cache, tg,
|md| md.data.name == crate_name) {
option::Some(md) => return md,
option::None => ()
}
let (_, work_dir) = get_file_path_and_dir(
cx.sess.working_dir.to_str(), crate_name);
let unit_metadata = ~[lltag(tg),
llunused(),
lli32(DW_LANG_RUST),
llstr(crate_name),
llstr(work_dir),
llstr(env!("CFG_VERSION")),
lli1(true), // deprecated: main compile unit
lli1(cx.sess.opts.optimize != session::No),
llstr(~""), // flags (???)
lli32(0) // runtime version (???)
];
let unit_node = llmdnode(unit_metadata);
add_named_metadata(cx, ~"llvm.dbg.cu", unit_node);
let mdval = @Metadata {
node: unit_node,
data: CompileUnitMetadata {
name: crate_name
}
};
update_cache(cache, tg, compile_unit_metadata(mdval));
return mdval;
}
fn get_cache(cx: @CrateContext) -> metadata_cache {
@ -710,114 +704,110 @@ fn create_var(type_tag: int, context: ValueRef, name: &str, file: ValueRef,
pub fn create_local_var(bcx: block, local: @ast::local)
-> @Metadata<LocalVarMetadata> {
unsafe {
let cx = bcx.ccx();
let cache = get_cache(cx);
let tg = AutoVariableTag;
match cached_metadata::<@Metadata<LocalVarMetadata>>(
cache, tg, |md| md.data.id == local.node.id) {
option::Some(md) => return md,
option::None => ()
}
let name = match local.node.pat.node {
ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth),
// FIXME this should be handled (#2533)
_ => fail!(~"no single variable name for local")
};
let loc = cx.sess.codemap.lookup_char_pos(local.span.lo);
let ty = node_id_type(bcx, local.node.id);
let tymd = create_ty(cx, ty, local.node.ty.span);
let filemd = create_file(cx, /*bad*/copy loc.file.name);
let context = match bcx.parent {
None => create_function(bcx.fcx).node,
Some(_) => create_block(bcx).node
};
let mdnode = create_var(tg, context, *cx.sess.str_of(name),
filemd.node, loc.line as int, tymd.node);
let mdval = @Metadata {
node: mdnode,
data: LocalVarMetadata {
id: local.node.id
}
};
update_cache(cache, AutoVariableTag, local_var_metadata(mdval));
let llptr = match bcx.fcx.lllocals.find(&local.node.id) {
option::Some(&local_mem(v)) => v,
option::Some(_) => {
bcx.tcx().sess.span_bug(local.span, ~"local is bound to \
something weird");
}
option::None => {
match *bcx.fcx.lllocals.get(&local.node.pat.id) {
local_imm(v) => v,
_ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \
something weird")
}
}
};
let declargs = ~[llmdnode(~[llptr]), mdnode];
trans::build::Call(bcx, *cx.intrinsics.get(&~"llvm.dbg.declare"),
declargs);
return mdval;
let cx = bcx.ccx();
let cache = get_cache(cx);
let tg = AutoVariableTag;
match cached_metadata::<@Metadata<LocalVarMetadata>>(
cache, tg, |md| md.data.id == local.node.id) {
option::Some(md) => return md,
option::None => ()
}
let name = match local.node.pat.node {
ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth),
// FIXME this should be handled (#2533)
_ => fail!(~"no single variable name for local")
};
let loc = cx.sess.codemap.lookup_char_pos(local.span.lo);
let ty = node_id_type(bcx, local.node.id);
let tymd = create_ty(cx, ty, local.node.ty.span);
let filemd = create_file(cx, /*bad*/copy loc.file.name);
let context = match bcx.parent {
None => create_function(bcx.fcx).node,
Some(_) => create_block(bcx).node
};
let mdnode = create_var(tg, context, *cx.sess.str_of(name),
filemd.node, loc.line as int, tymd.node);
let mdval = @Metadata {
node: mdnode,
data: LocalVarMetadata {
id: local.node.id
}
};
update_cache(cache, AutoVariableTag, local_var_metadata(mdval));
let llptr = match bcx.fcx.lllocals.find(&local.node.id) {
option::Some(&local_mem(v)) => v,
option::Some(_) => {
bcx.tcx().sess.span_bug(local.span, ~"local is bound to \
something weird");
}
option::None => {
match *bcx.fcx.lllocals.get(&local.node.pat.id) {
local_imm(v) => v,
_ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \
something weird")
}
}
};
let declargs = ~[llmdnode(~[llptr]), mdnode];
trans::build::Call(bcx, *cx.intrinsics.get(&~"llvm.dbg.declare"),
declargs);
return mdval;
}
pub fn create_arg(bcx: block, arg: ast::arg, sp: span)
-> Option<@Metadata<ArgumentMetadata>> {
unsafe {
let fcx = bcx.fcx, cx = *fcx.ccx;
let cache = get_cache(cx);
let tg = ArgVariableTag;
match cached_metadata::<@Metadata<ArgumentMetadata>>(
cache, ArgVariableTag, |md| md.data.id == arg.id) {
option::Some(md) => return Some(md),
option::None => ()
}
let fcx = bcx.fcx, cx = *fcx.ccx;
let cache = get_cache(cx);
let tg = ArgVariableTag;
match cached_metadata::<@Metadata<ArgumentMetadata>>(
cache, ArgVariableTag, |md| md.data.id == arg.id) {
option::Some(md) => return Some(md),
option::None => ()
}
let loc = cx.sess.codemap.lookup_char_pos(sp.lo);
if loc.file.name == ~"<intrinsic>" {
let loc = cx.sess.codemap.lookup_char_pos(sp.lo);
if loc.file.name == ~"<intrinsic>" {
return None;
}
let ty = node_id_type(bcx, arg.id);
let tymd = create_ty(cx, ty, arg.ty.span);
let filemd = create_file(cx, /*bad*/copy loc.file.name);
let context = create_function(bcx.fcx);
match arg.pat.node {
ast::pat_ident(_, path, _) => {
// XXX: This is wrong; it should work for multiple bindings.
let mdnode = create_var(
tg,
context.node,
*cx.sess.str_of(*path.idents.last()),
filemd.node,
loc.line as int,
tymd.node
);
let mdval = @Metadata {
node: mdnode,
data: ArgumentMetadata {
id: arg.id
}
};
update_cache(cache, tg, argument_metadata(mdval));
let llptr = match *fcx.llargs.get(&arg.id) {
local_mem(v) | local_imm(v) => v,
};
let declargs = ~[llmdnode(~[llptr]), mdnode];
trans::build::Call(bcx,
*cx.intrinsics.get(&~"llvm.dbg.declare"),
declargs);
return Some(mdval);
}
_ => {
return None;
}
let ty = node_id_type(bcx, arg.id);
let tymd = create_ty(cx, ty, arg.ty.span);
let filemd = create_file(cx, /*bad*/copy loc.file.name);
let context = create_function(bcx.fcx);
match arg.pat.node {
ast::pat_ident(_, path, _) => {
// XXX: This is wrong; it should work for multiple bindings.
let mdnode = create_var(
tg,
context.node,
*cx.sess.str_of(*path.idents.last()),
filemd.node,
loc.line as int,
tymd.node
);
let mdval = @Metadata {
node: mdnode,
data: ArgumentMetadata {
id: arg.id
}
};
update_cache(cache, tg, argument_metadata(mdval));
let llptr = match *fcx.llargs.get(&arg.id) {
local_mem(v) | local_imm(v) => v,
};
let declargs = ~[llmdnode(~[llptr]), mdnode];
trans::build::Call(bcx,
*cx.intrinsics.get(&~"llvm.dbg.declare"),
declargs);
return Some(mdval);
}
_ => {
return None;
}
}
}
}

View File

@ -300,7 +300,11 @@ struct ctxt_ {
destructors: @mut HashSet<ast::def_id>,
// Maps a trait onto a mapping from self-ty to impl
trait_impls: @mut HashMap<ast::def_id, @mut HashMap<t, @Impl>>
trait_impls: @mut HashMap<ast::def_id, @mut HashMap<t, @Impl>>,
// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
// present in this set can be warned about.
used_unsafe: @mut HashSet<ast::node_id>,
}
enum tbox_flag {
@ -885,7 +889,8 @@ pub fn mk_ctxt(s: session::Session,
supertraits: @mut HashMap::new(),
destructor_for_type: @mut HashMap::new(),
destructors: @mut HashSet::new(),
trait_impls: @mut HashMap::new()
trait_impls: @mut HashMap::new(),
used_unsafe: @mut HashSet::new(),
}
}
@ -4309,16 +4314,16 @@ pub fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr) -> uint {
}
// Determine what purity to check a nested function under
pub fn determine_inherited_purity(parent_purity: ast::purity,
child_purity: ast::purity,
child_sigil: ast::Sigil)
-> ast::purity {
pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id),
child: (ast::purity, ast::node_id),
child_sigil: ast::Sigil)
-> (ast::purity, ast::node_id) {
// If the closure is a stack closure and hasn't had some non-standard
// purity inferred for it, then check it under its parent's purity.
// Otherwise, use its own
match child_sigil {
ast::BorrowedSigil if child_purity == ast::impure_fn => parent_purity,
_ => child_purity
ast::BorrowedSigil if child.first() == ast::impure_fn => parent,
_ => child
}
}

View File

@ -179,6 +179,11 @@ pub enum FnKind {
Vanilla
}
struct PurityState {
purity: ast::purity,
from: ast::node_id,
}
pub struct FnCtxt {
// var_bindings, locals and next_var_id are shared
// with any nested functions that capture the environment
@ -187,7 +192,7 @@ pub struct FnCtxt {
ret_ty: ty::t,
// Used by loop bodies that return from the outer function
indirect_ret_ty: Option<ty::t>,
purity: ast::purity,
ps: PurityState,
// Sometimes we generate region pointers where the precise region
// to use is not known. For example, an expression like `&x.f`
@ -238,7 +243,7 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt,
@mut FnCtxt {
ret_ty: rty,
indirect_ret_ty: None,
purity: ast::pure_fn,
ps: PurityState { purity: ast::pure_fn, from: 0 },
region_lb: region_bnd,
in_scope_regions: @Nil,
fn_kind: Vanilla,
@ -265,7 +270,7 @@ pub fn check_bare_fn(ccx: @mut CrateCtxt,
ty::ty_bare_fn(ref fn_ty) => {
let fcx =
check_fn(ccx, self_info, fn_ty.purity,
&fn_ty.sig, decl, body, Vanilla,
&fn_ty.sig, decl, id, body, Vanilla,
@Nil, blank_inherited(ccx));;
vtable::resolve_in_block(fcx, body);
@ -282,6 +287,7 @@ pub fn check_fn(ccx: @mut CrateCtxt,
purity: ast::purity,
fn_sig: &ty::FnSig,
decl: &ast::fn_decl,
id: ast::node_id,
body: &ast::blk,
fn_kind: FnKind,
inherited_isr: isr_alist,
@ -342,7 +348,7 @@ pub fn check_fn(ccx: @mut CrateCtxt,
@mut FnCtxt {
ret_ty: ret_ty,
indirect_ret_ty: indirect_ret_ty,
purity: purity,
ps: PurityState { purity: purity, from: id },
region_lb: body.node.id,
in_scope_regions: isr,
fn_kind: fn_kind,
@ -867,8 +873,12 @@ pub impl FnCtxt {
}
fn require_unsafe(&self, sp: span, op: ~str) {
match self.purity {
ast::unsafe_fn => {/*ok*/}
match self.ps.purity {
ast::unsafe_fn => {
// ok, but flag that we used the source of unsafeness
debug!("flagging %? as a used unsafe source", self.ps.from);
self.tcx().used_unsafe.insert(self.ps.from);
}
_ => {
self.ccx.tcx.sess.span_err(
sp,
@ -1679,12 +1689,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
fcx.write_ty(expr.id, fty);
let inherited_purity =
ty::determine_inherited_purity(copy fcx.purity, purity,
let (inherited_purity, id) =
ty::determine_inherited_purity((fcx.ps.purity, fcx.ps.from),
(purity, expr.id),
sigil);
check_fn(fcx.ccx, None, inherited_purity, &fty_sig,
decl, body, fn_kind, fcx.in_scope_regions, fcx.inh);
decl, id, body, fn_kind, fcx.in_scope_regions, fcx.inh);
}
@ -2923,8 +2934,11 @@ pub fn check_block_with_expected(fcx0: @mut FnCtxt,
blk: &ast::blk,
expected: Option<ty::t>) {
let fcx = match blk.node.rules {
ast::unsafe_blk => @mut FnCtxt {purity: ast::unsafe_fn,.. copy *fcx0},
ast::default_blk => fcx0
ast::unsafe_blk => @mut FnCtxt {
ps: PurityState { purity: ast::unsafe_fn, from: blk.node.id },
.. copy *fcx0
},
ast::default_blk => fcx0
};
do fcx.with_region_lb(blk.node.id) {
let mut warned = false;

View File

@ -57,11 +57,9 @@ struct DtorRes {
#[unsafe_destructor]
impl Drop for DtorRes {
fn finalize(&self) {
unsafe {
match self.dtor {
option::None => (),
option::Some(f) => f()
}
match self.dtor {
option::None => (),
option::Some(f) => f()
}
}
}
@ -84,7 +82,7 @@ fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
* * base - A foreign pointer to a buffer
* * len - The number of elements in the buffer
*/
pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
pub fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
return CVec{
base: base,
len: len,
@ -103,7 +101,7 @@ pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
* * dtor - A function to run when the value is destructed, useful
* for freeing the buffer, etc.
*/
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: @fn())
pub fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: @fn())
-> CVec<T> {
return CVec{
base: base,
@ -144,7 +142,7 @@ pub fn set<T:Copy>(t: CVec<T>, ofs: uint, v: T) {
pub fn len<T>(t: CVec<T>) -> uint { t.len }
/// Returns a pointer to the first element of the vector
pub unsafe fn ptr<T>(t: CVec<T>) -> *mut T { t.base }
pub fn ptr<T>(t: CVec<T>) -> *mut T { t.base }
#[cfg(test)]
mod tests {

View File

@ -223,128 +223,126 @@ pub type Result = result::Result<Matches, Fail_>;
* Use <fail_str> to get an error message.
*/
pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
unsafe {
let n_opts = opts.len();
fn f(_x: uint) -> ~[Optval] { return ~[]; }
let mut vals = vec::from_fn(n_opts, f);
let mut free: ~[~str] = ~[];
let l = args.len();
let mut i = 0;
while i < l {
let cur = args[i];
let curlen = cur.len();
if !is_arg(cur) {
free.push(cur);
} else if cur == ~"--" {
let mut j = i + 1;
while j < l { free.push(args[j]); j += 1; }
break;
} else {
let mut names;
let mut i_arg = None;
if cur[1] == '-' as u8 {
let tail = str::slice(cur, 2, curlen).to_owned();
let mut tail_eq = ~[];
for str::each_splitn_char(tail, '=', 1) |s| { tail_eq.push(s.to_owned()) }
if tail_eq.len() <= 1 {
names = ~[Long(tail)];
} else {
names =
~[Long(tail_eq[0])];
i_arg = Some(tail_eq[1]);
}
let n_opts = opts.len();
fn f(_x: uint) -> ~[Optval] { return ~[]; }
let mut vals = vec::from_fn(n_opts, f);
let mut free: ~[~str] = ~[];
let l = args.len();
let mut i = 0;
while i < l {
let cur = args[i];
let curlen = cur.len();
if !is_arg(cur) {
free.push(cur);
} else if cur == ~"--" {
let mut j = i + 1;
while j < l { free.push(args[j]); j += 1; }
break;
} else {
let mut names;
let mut i_arg = None;
if cur[1] == '-' as u8 {
let tail = str::slice(cur, 2, curlen).to_owned();
let mut tail_eq = ~[];
for str::each_splitn_char(tail, '=', 1) |s| { tail_eq.push(s.to_owned()) }
if tail_eq.len() <= 1 {
names = ~[Long(tail)];
} else {
let mut j = 1;
let mut last_valid_opt_id = None;
names = ~[];
while j < curlen {
let range = str::char_range_at(cur, j);
let opt = Short(range.ch);
/* In a series of potential options (eg. -aheJ), if we
see one which takes an argument, we assume all
subsequent characters make up the argument. This
allows options such as -L/usr/local/lib/foo to be
interpreted correctly
*/
match find_opt(opts, opt) {
Some(id) => last_valid_opt_id = Some(id),
None => {
let arg_follows =
last_valid_opt_id.is_some() &&
match opts[last_valid_opt_id.get()]
.hasarg {
Yes | Maybe => true,
No => false
};
if arg_follows && j < curlen {
i_arg = Some(cur.slice(j, curlen).to_owned());
break;
} else {
last_valid_opt_id = None;
}
}
}
names.push(opt);
j = range.next;
}
names =
~[Long(tail_eq[0])];
i_arg = Some(tail_eq[1]);
}
let mut name_pos = 0;
for names.each() |nm| {
name_pos += 1;
let optid = match find_opt(opts, *nm) {
Some(id) => id,
None => return Err(UnrecognizedOption(name_str(nm)))
};
match opts[optid].hasarg {
No => {
if !i_arg.is_none() {
return Err(UnexpectedArgument(name_str(nm)));
} else {
let mut j = 1;
let mut last_valid_opt_id = None;
names = ~[];
while j < curlen {
let range = str::char_range_at(cur, j);
let opt = Short(range.ch);
/* In a series of potential options (eg. -aheJ), if we
see one which takes an argument, we assume all
subsequent characters make up the argument. This
allows options such as -L/usr/local/lib/foo to be
interpreted correctly
*/
match find_opt(opts, opt) {
Some(id) => last_valid_opt_id = Some(id),
None => {
let arg_follows =
last_valid_opt_id.is_some() &&
match opts[last_valid_opt_id.get()]
.hasarg {
Yes | Maybe => true,
No => false
};
if arg_follows && j < curlen {
i_arg = Some(cur.slice(j, curlen).to_owned());
break;
} else {
last_valid_opt_id = None;
}
}
}
names.push(opt);
j = range.next;
}
}
let mut name_pos = 0;
for names.each() |nm| {
name_pos += 1;
let optid = match find_opt(opts, *nm) {
Some(id) => id,
None => return Err(UnrecognizedOption(name_str(nm)))
};
match opts[optid].hasarg {
No => {
if !i_arg.is_none() {
return Err(UnexpectedArgument(name_str(nm)));
}
vals[optid].push(Given);
}
Maybe => {
if !i_arg.is_none() {
vals[optid].push(Val(i_arg.get()));
} else if name_pos < names.len() ||
i + 1 == l || is_arg(args[i + 1]) {
vals[optid].push(Given);
}
Maybe => {
if !i_arg.is_none() {
vals[optid].push(Val(i_arg.get()));
} else if name_pos < names.len() ||
i + 1 == l || is_arg(args[i + 1]) {
vals[optid].push(Given);
} else { i += 1; vals[optid].push(Val(args[i])); }
}
Yes => {
if !i_arg.is_none() {
vals[optid].push(Val(i_arg.get()));
} else if i + 1 == l {
return Err(ArgumentMissing(name_str(nm)));
} else { i += 1; vals[optid].push(Val(args[i])); }
}
}
} else { i += 1; vals[optid].push(Val(args[i])); }
}
Yes => {
if !i_arg.is_none() {
vals[optid].push(Val(i_arg.get()));
} else if i + 1 == l {
return Err(ArgumentMissing(name_str(nm)));
} else { i += 1; vals[optid].push(Val(args[i])); }
}
}
}
i += 1;
}
i = 0u;
while i < n_opts {
let n = vals[i].len();
let occ = opts[i].occur;
if occ == Req {
if n == 0 {
return Err(OptionMissing(name_str(&(opts[i].name))));
}
}
if occ != Multi {
if n > 1 {
return Err(OptionDuplicated(name_str(&(opts[i].name))));
}
}
i += 1;
}
return Ok(Matches {opts: vec::from_slice(opts),
vals: vals,
free: free});
i += 1;
}
i = 0u;
while i < n_opts {
let n = vals[i].len();
let occ = opts[i].occur;
if occ == Req {
if n == 0 {
return Err(OptionMissing(name_str(&(opts[i].name))));
}
}
if occ != Multi {
if n > 1 {
return Err(OptionDuplicated(name_str(&(opts[i].name))));
}
}
i += 1;
}
return Ok(Matches {opts: vec::from_slice(opts),
vals: vals,
free: free});
}
fn opt_vals(mm: &Matches, nm: &str) -> ~[Optval] {

View File

@ -116,35 +116,33 @@ pub fn get_addr(node: &str, iotask: &iotask)
let mut output_ch = Some(SharedChan(output_ch));
do str::as_buf(node) |node_ptr, len| {
let output_ch = output_ch.swap_unwrap();
unsafe {
debug!("slice len %?", len);
let handle = create_uv_getaddrinfo_t();
let handle_ptr = ptr::addr_of(&handle);
let handle_data = GetAddrData {
output_ch: output_ch.clone()
};
let handle_data_ptr = ptr::addr_of(&handle_data);
do interact(iotask) |loop_ptr| {
unsafe {
let result = uv_getaddrinfo(
loop_ptr,
handle_ptr,
get_addr_cb,
node_ptr,
ptr::null(),
ptr::null());
match result {
0i32 => {
set_data_for_req(handle_ptr, handle_data_ptr);
}
_ => {
output_ch.send(result::Err(GetAddrUnknownError));
}
debug!("slice len %?", len);
let handle = create_uv_getaddrinfo_t();
let handle_ptr = ptr::addr_of(&handle);
let handle_data = GetAddrData {
output_ch: output_ch.clone()
};
let handle_data_ptr = ptr::addr_of(&handle_data);
do interact(iotask) |loop_ptr| {
unsafe {
let result = uv_getaddrinfo(
loop_ptr,
handle_ptr,
get_addr_cb,
node_ptr,
ptr::null(),
ptr::null());
match result {
0i32 => {
set_data_for_req(handle_ptr, handle_data_ptr);
}
_ => {
output_ch.send(result::Err(GetAddrUnknownError));
}
}
};
output_po.recv()
}
}
};
output_po.recv()
}
}

View File

@ -57,9 +57,7 @@ pub struct TcpSocket {
#[unsafe_destructor]
impl Drop for TcpSocket {
fn finalize(&self) {
unsafe {
tear_down_socket_data(self.socket_data)
}
tear_down_socket_data(self.socket_data)
}
}
@ -302,11 +300,10 @@ pub fn connect(input_ip: ip::IpAddr, port: uint,
* `TcpErrData` value as the `Err` variant
*/
pub fn write(sock: &TcpSocket, raw_write_data: ~[u8])
-> result::Result<(), TcpErrData> {
unsafe {
let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data)));
write_common_impl(socket_data_ptr, raw_write_data)
}
-> result::Result<(), TcpErrData>
{
let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data)));
write_common_impl(socket_data_ptr, raw_write_data)
}
/**
@ -341,13 +338,12 @@ pub fn write(sock: &TcpSocket, raw_write_data: ~[u8])
* value as the `Err` variant
*/
pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8])
-> future::Future<result::Result<(), TcpErrData>> {
unsafe {
let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data)));
do future_spawn {
let data_copy = copy(raw_write_data);
write_common_impl(socket_data_ptr, data_copy)
}
-> future::Future<result::Result<(), TcpErrData>>
{
let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data)));
do future_spawn {
let data_copy = copy(raw_write_data);
write_common_impl(socket_data_ptr, data_copy)
}
}
@ -369,10 +365,8 @@ pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8])
pub fn read_start(sock: &TcpSocket)
-> result::Result<@Port<
result::Result<~[u8], TcpErrData>>, TcpErrData> {
unsafe {
let socket_data = ptr::addr_of(&(*(sock.socket_data)));
read_start_common_impl(socket_data)
}
let socket_data = ptr::addr_of(&(*(sock.socket_data)));
read_start_common_impl(socket_data)
}
/**
@ -382,12 +376,9 @@ pub fn read_start(sock: &TcpSocket)
*
* * `sock` - a `net::tcp::TcpSocket` that you wish to stop reading on
*/
pub fn read_stop(sock: &TcpSocket) ->
result::Result<(), TcpErrData> {
unsafe {
let socket_data = ptr::addr_of(&(*sock.socket_data));
read_stop_common_impl(socket_data)
}
pub fn read_stop(sock: &TcpSocket) -> result::Result<(), TcpErrData> {
let socket_data = ptr::addr_of(&(*sock.socket_data));
read_stop_common_impl(socket_data)
}
/**
@ -654,150 +645,148 @@ fn listen_common(host_ip: ip::IpAddr,
on_establish_cb: ~fn(SharedChan<Option<TcpErrData>>),
on_connect_cb: ~fn(*uv::ll::uv_tcp_t))
-> result::Result<(), TcpListenErrData> {
unsafe {
let (stream_closed_po, stream_closed_ch) = stream::<()>();
let stream_closed_ch = SharedChan(stream_closed_ch);
let (kill_po, kill_ch) = stream::<Option<TcpErrData>>();
let kill_ch = SharedChan(kill_ch);
let server_stream = uv::ll::tcp_t();
let server_stream_ptr = ptr::addr_of(&server_stream);
let server_data: TcpListenFcData = TcpListenFcData {
server_stream_ptr: server_stream_ptr,
stream_closed_ch: stream_closed_ch,
kill_ch: kill_ch.clone(),
on_connect_cb: on_connect_cb,
iotask: iotask.clone(),
ipv6: match &host_ip {
&ip::Ipv4(_) => { false }
&ip::Ipv6(_) => { true }
},
mut active: true
};
let server_data_ptr = ptr::addr_of(&server_data);
let (stream_closed_po, stream_closed_ch) = stream::<()>();
let stream_closed_ch = SharedChan(stream_closed_ch);
let (kill_po, kill_ch) = stream::<Option<TcpErrData>>();
let kill_ch = SharedChan(kill_ch);
let server_stream = uv::ll::tcp_t();
let server_stream_ptr = ptr::addr_of(&server_stream);
let server_data: TcpListenFcData = TcpListenFcData {
server_stream_ptr: server_stream_ptr,
stream_closed_ch: stream_closed_ch,
kill_ch: kill_ch.clone(),
on_connect_cb: on_connect_cb,
iotask: iotask.clone(),
ipv6: match &host_ip {
&ip::Ipv4(_) => { false }
&ip::Ipv6(_) => { true }
},
mut active: true
};
let server_data_ptr = ptr::addr_of(&server_data);
let (setup_po, setup_ch) = stream();
let (setup_po, setup_ch) = stream();
// this is to address a compiler warning about
// an implicit copy.. it seems that double nested
// will defeat a move sigil, as is done to the host_ip
// arg above.. this same pattern works w/o complaint in
// tcp::connect (because the iotask::interact cb isn't
// nested within a core::comm::listen block)
let loc_ip = copy(host_ip);
do iotask::interact(iotask) |loop_ptr| {
unsafe {
match uv::ll::tcp_init(loop_ptr, server_stream_ptr) {
0i32 => {
uv::ll::set_data_for_uv_handle(
server_stream_ptr,
server_data_ptr);
let addr_str = ip::format_addr(&loc_ip);
let bind_result = match loc_ip {
ip::Ipv4(ref addr) => {
debug!("addr: %?", addr);
let in_addr = uv::ll::ip4_addr(
addr_str,
port as int);
uv::ll::tcp_bind(server_stream_ptr,
ptr::addr_of(&in_addr))
}
ip::Ipv6(ref addr) => {
debug!("addr: %?", addr);
let in_addr = uv::ll::ip6_addr(
addr_str,
port as int);
uv::ll::tcp_bind6(server_stream_ptr,
ptr::addr_of(&in_addr))
}
};
match bind_result {
0i32 => {
match uv::ll::listen(
server_stream_ptr,
backlog as libc::c_int,
tcp_lfc_on_connection_cb) {
0i32 => setup_ch.send(None),
_ => {
debug!(
"failure to uv_tcp_init");
let err_data =
uv::ll::get_last_err_data(
loop_ptr);
setup_ch.send(Some(err_data));
}
// this is to address a compiler warning about
// an implicit copy.. it seems that double nested
// will defeat a move sigil, as is done to the host_ip
// arg above.. this same pattern works w/o complaint in
// tcp::connect (because the iotask::interact cb isn't
// nested within a core::comm::listen block)
let loc_ip = copy(host_ip);
do iotask::interact(iotask) |loop_ptr| {
unsafe {
match uv::ll::tcp_init(loop_ptr, server_stream_ptr) {
0i32 => {
uv::ll::set_data_for_uv_handle(
server_stream_ptr,
server_data_ptr);
let addr_str = ip::format_addr(&loc_ip);
let bind_result = match loc_ip {
ip::Ipv4(ref addr) => {
debug!("addr: %?", addr);
let in_addr = uv::ll::ip4_addr(
addr_str,
port as int);
uv::ll::tcp_bind(server_stream_ptr,
ptr::addr_of(&in_addr))
}
ip::Ipv6(ref addr) => {
debug!("addr: %?", addr);
let in_addr = uv::ll::ip6_addr(
addr_str,
port as int);
uv::ll::tcp_bind6(server_stream_ptr,
ptr::addr_of(&in_addr))
}
};
match bind_result {
0i32 => {
match uv::ll::listen(
server_stream_ptr,
backlog as libc::c_int,
tcp_lfc_on_connection_cb) {
0i32 => setup_ch.send(None),
_ => {
debug!(
"failure to uv_tcp_init");
let err_data =
uv::ll::get_last_err_data(
loop_ptr);
setup_ch.send(Some(err_data));
}
}
_ => {
debug!("failure to uv_tcp_bind");
let err_data = uv::ll::get_last_err_data(
loop_ptr);
setup_ch.send(Some(err_data));
}
}
_ => {
debug!("failure to uv_tcp_bind");
let err_data = uv::ll::get_last_err_data(
loop_ptr);
setup_ch.send(Some(err_data));
}
}
_ => {
debug!("failure to uv_tcp_bind");
let err_data = uv::ll::get_last_err_data(
loop_ptr);
setup_ch.send(Some(err_data));
}
}
_ => {
debug!("failure to uv_tcp_bind");
let err_data = uv::ll::get_last_err_data(
loop_ptr);
setup_ch.send(Some(err_data));
}
}
}
}
let setup_result = setup_po.recv();
let setup_result = setup_po.recv();
match setup_result {
Some(ref err_data) => {
do iotask::interact(iotask) |loop_ptr| {
unsafe {
debug!(
"tcp::listen post-kill recv hl interact %?",
loop_ptr);
(*server_data_ptr).active = false;
uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
}
};
stream_closed_po.recv();
match err_data.err_name {
~"EACCES" => {
debug!("Got EACCES error");
result::Err(AccessDenied)
}
~"EADDRINUSE" => {
debug!("Got EADDRINUSE error");
result::Err(AddressInUse)
}
_ => {
debug!("Got '%s' '%s' libuv error",
err_data.err_name, err_data.err_msg);
result::Err(
GenericListenErr(err_data.err_name,
err_data.err_msg))
}
match setup_result {
Some(ref err_data) => {
do iotask::interact(iotask) |loop_ptr| {
unsafe {
debug!(
"tcp::listen post-kill recv hl interact %?",
loop_ptr);
(*server_data_ptr).active = false;
uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
}
};
stream_closed_po.recv();
match err_data.err_name {
~"EACCES" => {
debug!("Got EACCES error");
result::Err(AccessDenied)
}
~"EADDRINUSE" => {
debug!("Got EADDRINUSE error");
result::Err(AddressInUse)
}
_ => {
debug!("Got '%s' '%s' libuv error",
err_data.err_name, err_data.err_msg);
result::Err(
GenericListenErr(err_data.err_name,
err_data.err_msg))
}
}
None => {
on_establish_cb(kill_ch.clone());
let kill_result = kill_po.recv();
do iotask::interact(iotask) |loop_ptr| {
unsafe {
debug!(
"tcp::listen post-kill recv hl interact %?",
loop_ptr);
(*server_data_ptr).active = false;
uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
}
};
stream_closed_po.recv();
match kill_result {
// some failure post bind/listen
Some(ref err_data) => result::Err(GenericListenErr(
err_data.err_name,
err_data.err_msg)),
// clean exit
None => result::Ok(())
}
None => {
on_establish_cb(kill_ch.clone());
let kill_result = kill_po.recv();
do iotask::interact(iotask) |loop_ptr| {
unsafe {
debug!(
"tcp::listen post-kill recv hl interact %?",
loop_ptr);
(*server_data_ptr).active = false;
uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
}
};
stream_closed_po.recv();
match kill_result {
// some failure post bind/listen
Some(ref err_data) => result::Err(GenericListenErr(
err_data.err_name,
err_data.err_msg)),
// clean exit
None => result::Ok(())
}
}
}
@ -1382,9 +1371,7 @@ extern fn stream_error_close_cb(handle: *uv::ll::uv_tcp_t) {
}
extern fn tcp_connect_close_cb(handle: *uv::ll::uv_tcp_t) {
unsafe {
debug!("closed client tcp handle %?", handle);
}
debug!("closed client tcp handle %?", handle);
}
extern fn tcp_connect_on_connect_cb(connect_req_ptr: *uv::ll::uv_connect_t,

View File

@ -118,8 +118,7 @@ fn encode_inner(s: &str, full_url: bool) -> ~str {
* This function is compliant with RFC 3986.
*/
pub fn encode(s: &str) -> ~str {
// FIXME(#3722): unsafe only because encode_inner does (string) IO
unsafe {encode_inner(s, true)}
encode_inner(s, true)
}
/**
@ -130,8 +129,7 @@ pub fn encode(s: &str) -> ~str {
*/
pub fn encode_component(s: &str) -> ~str {
// FIXME(#3722): unsafe only because encode_inner does (string) IO
unsafe {encode_inner(s, false)}
encode_inner(s, false)
}
fn decode_inner(s: &str, full_url: bool) -> ~str {
@ -178,16 +176,14 @@ fn decode_inner(s: &str, full_url: bool) -> ~str {
* This will only decode escape sequences generated by encode.
*/
pub fn decode(s: &str) -> ~str {
// FIXME(#3722): unsafe only because decode_inner does (string) IO
unsafe {decode_inner(s, true)}
decode_inner(s, true)
}
/**
* Decode a string encoded with percent encoding.
*/
pub fn decode_component(s: &str) -> ~str {
// FIXME(#3722): unsafe only because decode_inner does (string) IO
unsafe {decode_inner(s, false)}
decode_inner(s, false)
}
fn encode_plus(s: &str) -> ~str {
@ -301,18 +297,15 @@ fn split_char_first(s: &str, c: char) -> (~str, ~str) {
let len = str::len(s);
let mut index = len;
let mut mat = 0;
// FIXME(#3722): unsafe only because decode_inner does (string) IO
unsafe {
do io::with_str_reader(s) |rdr| {
let mut ch;
while !rdr.eof() {
ch = rdr.read_byte() as char;
if ch == c {
// found a match, adjust markers
index = rdr.tell()-1;
mat = 1;
break;
}
do io::with_str_reader(s) |rdr| {
let mut ch;
while !rdr.eof() {
ch = rdr.read_byte() as char;
if ch == c {
// found a match, adjust markers
index = rdr.tell()-1;
mat = 1;
break;
}
}
}
@ -346,29 +339,25 @@ fn query_from_str(rawquery: &str) -> Query {
if str::len(rawquery) != 0 {
for str::each_split_char(rawquery, '&') |p| {
let (k, v) = split_char_first(p, '=');
// FIXME(#3722): unsafe only because decode_inner does (string) IO
unsafe {query.push((decode_component(k), decode_component(v)));}
query.push((decode_component(k), decode_component(v)));
};
}
return query;
}
pub fn query_to_str(query: &Query) -> ~str {
unsafe {
// FIXME(#3722): unsafe only because decode_inner does (string) IO
let mut strvec = ~[];
for query.each |kv| {
match kv {
&(ref k, ref v) => {
strvec.push(fmt!("%s=%s",
encode_component(*k),
encode_component(*v))
);
}
let mut strvec = ~[];
for query.each |kv| {
match kv {
&(ref k, ref v) => {
strvec.push(fmt!("%s=%s",
encode_component(*k),
encode_component(*v))
);
}
}
return str::connect(strvec, ~"&");
}
return str::connect(strvec, ~"&");
}
// returns the scheme and the rest of the url, or a parsing error

View File

@ -59,12 +59,10 @@ pub unsafe fn load_history(file: ~str) -> bool {
/// Print out a prompt and then wait for input and return it
pub unsafe fn read(prompt: ~str) -> Option<~str> {
do str::as_c_str(prompt) |buf| {
unsafe {
let line = rustrt::linenoise(buf);
let line = rustrt::linenoise(buf);
if line.is_null() { None }
else { Some(str::raw::from_c_str(line)) }
}
if line.is_null() { None }
else { Some(str::raw::from_c_str(line)) }
}
}
@ -74,22 +72,20 @@ fn complete_key(_v: @CompletionCb) {}
/// Bind to the main completion callback
pub unsafe fn complete(cb: CompletionCb) {
unsafe {
task::local_data::local_data_set(complete_key, @(cb));
task::local_data::local_data_set(complete_key, @(cb));
extern fn callback(line: *c_char, completions: *()) {
unsafe {
let cb = *task::local_data::local_data_get(complete_key)
.get();
extern fn callback(line: *c_char, completions: *()) {
unsafe {
let cb = *task::local_data::local_data_get(complete_key)
.get();
do cb(str::raw::from_c_str(line)) |suggestion| {
do str::as_c_str(suggestion) |buf| {
rustrt::linenoiseAddCompletion(completions, buf);
}
do cb(str::raw::from_c_str(line)) |suggestion| {
do str::as_c_str(suggestion) |buf| {
rustrt::linenoiseAddCompletion(completions, buf);
}
}
}
rustrt::linenoiseSetCompletionCallback(callback);
}
rustrt::linenoiseSetCompletionCallback(callback);
}

View File

@ -862,17 +862,15 @@ pub mod node {
* This function executes in linear time.
*/
pub fn flatten(node: @Node) -> @Node {
unsafe {
match (*node) {
Leaf(_) => node,
Concat(ref x) => {
@Leaf(Leaf {
byte_offset: 0u,
byte_len: x.byte_len,
char_len: x.char_len,
content: @serialize_node(node),
})
}
match (*node) {
Leaf(_) => node,
Concat(ref x) => {
@Leaf(Leaf {
byte_offset: 0u,
byte_len: x.byte_len,
char_len: x.char_len,
content: @serialize_node(node),
})
}
}
}

View File

@ -101,17 +101,15 @@ fn new_sem_and_signal(count: int, num_condvars: uint)
pub impl<Q:Owned> Sem<Q> {
fn acquire(&self) {
let mut waiter_nobe = None;
unsafe {
do (**self).with |state| {
state.count -= 1;
if state.count < 0 {
// Create waiter nobe.
let (WaitEnd, SignalEnd) = comm::oneshot();
// Tell outer scope we need to block.
waiter_nobe = Some(WaitEnd);
// Enqueue ourself.
state.waiters.tail.send(SignalEnd);
}
do (**self).with |state| {
state.count -= 1;
if state.count < 0 {
// Create waiter nobe.
let (WaitEnd, SignalEnd) = comm::oneshot();
// Tell outer scope we need to block.
waiter_nobe = Some(WaitEnd);
// Enqueue ourself.
state.waiters.tail.send(SignalEnd);
}
}
// Uncomment if you wish to test for sem races. Not valgrind-friendly.
@ -122,12 +120,10 @@ pub impl<Q:Owned> Sem<Q> {
}
}
fn release(&self) {
unsafe {
do (**self).with |state| {
state.count += 1;
if state.count <= 0 {
signal_waitqueue(&state.waiters);
}
do (**self).with |state| {
state.count += 1;
if state.count <= 0 {
signal_waitqueue(&state.waiters);
}
}
}
@ -169,9 +165,7 @@ struct SemReleaseGeneric<'self, Q> { sem: &'self Sem<Q> }
#[unsafe_destructor]
impl<'self, Q:Owned> Drop for SemReleaseGeneric<'self, Q> {
fn finalize(&self) {
unsafe {
self.sem.release();
}
self.sem.release();
}
}
@ -291,13 +285,11 @@ pub impl<'self> Condvar<'self> {
fn signal_on(&self, condvar_id: uint) -> bool {
let mut out_of_bounds = None;
let mut result = false;
unsafe {
do (**self.sem).with |state| {
if condvar_id < vec::len(state.blocked) {
result = signal_waitqueue(&state.blocked[condvar_id]);
} else {
out_of_bounds = Some(vec::len(state.blocked));
}
do (**self.sem).with |state| {
if condvar_id < vec::len(state.blocked) {
result = signal_waitqueue(&state.blocked[condvar_id]);
} else {
out_of_bounds = Some(vec::len(state.blocked));
}
}
do check_cvar_bounds(out_of_bounds, condvar_id, "cond.signal_on()") {
@ -312,17 +304,15 @@ pub impl<'self> Condvar<'self> {
fn broadcast_on(&self, condvar_id: uint) -> uint {
let mut out_of_bounds = None;
let mut queue = None;
unsafe {
do (**self.sem).with |state| {
if condvar_id < vec::len(state.blocked) {
// To avoid :broadcast_heavy, we make a new waitqueue,
// swap it out with the old one, and broadcast on the
// old one outside of the little-lock.
queue = Some(util::replace(&mut state.blocked[condvar_id],
new_waitqueue()));
} else {
out_of_bounds = Some(vec::len(state.blocked));
}
do (**self.sem).with |state| {
if condvar_id < vec::len(state.blocked) {
// To avoid :broadcast_heavy, we make a new waitqueue,
// swap it out with the old one, and broadcast on the
// old one outside of the little-lock.
queue = Some(util::replace(&mut state.blocked[condvar_id],
new_waitqueue()));
} else {
out_of_bounds = Some(vec::len(state.blocked));
}
}
do check_cvar_bounds(out_of_bounds, condvar_id, "cond.signal_on()") {

View File

@ -42,47 +42,45 @@ pub fn delayed_send<T:Owned>(iotask: &IoTask,
msecs: uint,
ch: &Chan<T>,
val: T) {
let (timer_done_po, timer_done_ch) = stream::<()>();
let timer_done_ch = SharedChan(timer_done_ch);
let timer = uv::ll::timer_t();
let timer_ptr = ptr::addr_of(&timer);
do iotask::interact(iotask) |loop_ptr| {
unsafe {
let (timer_done_po, timer_done_ch) = stream::<()>();
let timer_done_ch = SharedChan(timer_done_ch);
let timer = uv::ll::timer_t();
let timer_ptr = ptr::addr_of(&timer);
do iotask::interact(iotask) |loop_ptr| {
unsafe {
let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
if (init_result == 0i32) {
let start_result = uv::ll::timer_start(
timer_ptr, delayed_send_cb, msecs, 0u);
if (start_result == 0i32) {
// Note: putting the channel into a ~
// to cast to *c_void
let timer_done_ch_clone = ~timer_done_ch.clone();
let timer_done_ch_ptr = transmute::<
~SharedChan<()>, *c_void>(
timer_done_ch_clone);
uv::ll::set_data_for_uv_handle(
timer_ptr,
timer_done_ch_ptr);
} else {
let error_msg = uv::ll::get_last_err_info(
loop_ptr);
fail!(~"timer::delayed_send() start failed: " +
error_msg);
}
} else {
let error_msg = uv::ll::get_last_err_info(loop_ptr);
fail!(~"timer::delayed_send() init failed: " +
error_msg);
}
let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
if (init_result == 0i32) {
let start_result = uv::ll::timer_start(
timer_ptr, delayed_send_cb, msecs, 0u);
if (start_result == 0i32) {
// Note: putting the channel into a ~
// to cast to *c_void
let timer_done_ch_clone = ~timer_done_ch.clone();
let timer_done_ch_ptr = transmute::<
~SharedChan<()>, *c_void>(
timer_done_ch_clone);
uv::ll::set_data_for_uv_handle(
timer_ptr,
timer_done_ch_ptr);
} else {
let error_msg = uv::ll::get_last_err_info(
loop_ptr);
fail!(~"timer::delayed_send() start failed: " +
error_msg);
}
};
// delayed_send_cb has been processed by libuv
timer_done_po.recv();
// notify the caller immediately
ch.send(val);
// uv_close for this timer has been processed
timer_done_po.recv();
} else {
let error_msg = uv::ll::get_last_err_info(loop_ptr);
fail!(~"timer::delayed_send() init failed: " +
error_msg);
}
}
};
// delayed_send_cb has been processed by libuv
timer_done_po.recv();
// notify the caller immediately
ch.send(val);
// uv_close for this timer has been processed
timer_done_po.recv();
}
/**

View File

@ -75,7 +75,7 @@ pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask {
* module. It is not safe to send the `loop_ptr` param to this callback out
* via ports/chans.
*/
pub unsafe fn interact(iotask: &IoTask, cb: ~fn(*c_void)) {
pub fn interact(iotask: &IoTask, cb: ~fn(*c_void)) {
send_msg(iotask, Interaction(cb));
}
@ -87,9 +87,7 @@ pub unsafe fn interact(iotask: &IoTask, cb: ~fn(*c_void)) {
* closed, causing a failure otherwise.
*/
pub fn exit(iotask: &IoTask) {
unsafe {
send_msg(iotask, TeardownLoop);
}
send_msg(iotask, TeardownLoop);
}

View File

@ -1111,22 +1111,22 @@ pub unsafe fn freeaddrinfo(res: *addrinfo) {
}
// libuv struct initializers
pub unsafe fn tcp_t() -> uv_tcp_t {
pub fn tcp_t() -> uv_tcp_t {
return uv_ll_struct_stubgen::gen_stub_uv_tcp_t();
}
pub unsafe fn connect_t() -> uv_connect_t {
pub fn connect_t() -> uv_connect_t {
return uv_ll_struct_stubgen::gen_stub_uv_connect_t();
}
pub unsafe fn write_t() -> uv_write_t {
pub fn write_t() -> uv_write_t {
return uv_ll_struct_stubgen::gen_stub_uv_write_t();
}
pub unsafe fn async_t() -> uv_async_t {
pub fn async_t() -> uv_async_t {
return uv_ll_struct_stubgen::gen_stub_uv_async_t();
}
pub unsafe fn timer_t() -> uv_timer_t {
pub fn timer_t() -> uv_timer_t {
return uv_ll_struct_stubgen::gen_stub_uv_timer_t();
}
pub unsafe fn getaddrinfo_t() -> uv_getaddrinfo_t {
pub fn getaddrinfo_t() -> uv_getaddrinfo_t {
return uv_ll_struct_stubgen::gen_stub_uv_getaddrinfo_t();
}

View File

@ -274,13 +274,11 @@ impl ToStr for Abi {
impl ToStr for AbiSet {
fn to_str(&self) -> ~str {
unsafe { // so we can push to strs.
let mut strs = ~[];
for self.each |abi| {
strs.push(abi.data().name);
}
fmt!("\"%s\"", str::connect_slices(strs, " "))
let mut strs = ~[];
for self.each |abi| {
strs.push(abi.data().name);
}
fmt!("\"%s\"", str::connect_slices(strs, " "))
}
}

View File

@ -0,0 +1,44 @@
// 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 <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.
// Exercise the unused_unsafe attribute in some positive and negative cases
#[deny(unused_unsafe)];
use core::libc;
fn callback<T>(_f: &fn() -> T) -> T { fail!() }
fn bad1() { unsafe {} } //~ ERROR: unnecessary "unsafe" block
fn bad2() { unsafe { bad1() } } //~ ERROR: unnecessary "unsafe" block
unsafe fn bad3() {} //~ ERROR: unnecessary "unsafe" function
unsafe fn bad4() { unsafe {} } //~ ERROR: unnecessary "unsafe" function
//~^ ERROR: unnecessary "unsafe" block
fn bad5() { unsafe { do callback {} } } //~ ERROR: unnecessary "unsafe" block
unsafe fn good0() { libc::exit(1) }
fn good1() { unsafe { libc::exit(1) } }
fn good2() {
/* bug uncovered when implementing warning about unused unsafe blocks. Be
sure that when purity is inherited that the source of the unsafe-ness
is tracked correctly */
unsafe {
unsafe fn what() -> ~[~str] { libc::exit(2) }
do callback {
what();
}
}
}
#[allow(unused_unsafe)] unsafe fn allowed0() {}
#[allow(unused_unsafe)] fn allowed1() { unsafe {} }
fn main() { }