Follow up to #8619 (step 3 of 5).
(See #8527, which was step 1 of 5, for the full outline.)
Part of #7081.
#, no-wrap
msgid ""
"~~~\n"
-"impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {\n"
-" pub fn from_iterator(iterator: &mut T) -> ~[A] {\n"
+"impl<A> FromIterator<A> for ~[A] {\n"
+" pub fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {\n"
" let (lower, _) = iterator.size_hint();\n"
" let mut xs = with_capacity(lower);\n"
" for x in iterator {\n"
Each source file contains a sequence of zero or more `item` definitions,
and may optionally begin with any number of `attributes` that apply to the containing module.
-Atributes on the anonymous crate module define important metadata that influences
+Attributes on the anonymous crate module define important metadata that influences
the behavior of the compiler.
~~~~~~~~
In type-parameterized functions,
methods of the supertrait may be called on values of subtrait-bound type parameters.
-Refering to the previous example of `trait Circle : Shape`:
+Referring to the previous example of `trait Circle : Shape`:
~~~
# trait Shape { fn area(&self) -> float; }
When the field is mutable, it can be [assigned](#assignment-expressions) to.
When the type of the expression to the left of the dot is a pointer to a record or structure,
-it is automatically derferenced to make the field access possible.
+it is automatically dereferenced to make the field access possible.
### Vector expressions
* `iter()` and `rev_iter()`, for immutable references to the elements
* `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements
-* `consume_iter()` and `consume_rev_iter`, to move the elements out by-value
+* `move_iter()` and `move_rev_iter`, to move the elements out by-value
A typical mutable container will implement at least `iter()`, `mut_iter()` and
-`consume_iter()` along with the reverse variants if it maintains an order.
+`move_iter()` along with the reverse variants if it maintains an order.
### Freezing
## Iterator adaptors
-The `IteratorUtil` trait implements common algorithms as methods extending
-every `Iterator` implementation. For example, the `fold` method will accumulate
-the items yielded by an `Iterator` into a single value:
+The `Iterator` trait provides many common algorithms as default methods. For
+example, the `fold` method will accumulate the items yielded by an `Iterator`
+into a single value:
~~~
let xs = [1, 9, 2, 3, 14, 12];
~~~
let xs = [1, 9, 2, 3, 14, 12];
let ys = [5, 2, 1, 8];
-let sum = xs.iter().chain_(ys.iter()).fold(0, |a, b| a + *b);
+let sum = xs.iter().chain(ys.iter()).fold(0, |a, b| a + *b);
assert_eq!(sum, 57);
~~~
-Note that some adaptors like the `chain_` method above use a trailing
-underscore to work around an issue with method resolve. The underscores will be
-dropped when they become unnecessary.
-
## For loops
The `for` keyword can be used as sugar for iterating through any iterator:
~~~
let xs = [0, 1, 1, 2, 3, 5, 8];
-let ys = xs.rev_iter().skip(1).transform(|&x| x * 2).collect::<~[int]>();
+let ys = xs.rev_iter().skip(1).map(|&x| x * 2).collect::<~[int]>();
assert_eq!(ys, ~[10, 6, 4, 2, 2, 0]);
~~~
vectors is as follows:
~~~
-impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
- pub fn from_iterator(iterator: &mut T) -> ~[A] {
+impl<A> FromIterator<A> for ~[A] {
+ pub fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
let mut xs = with_capacity(lower);
for x in iterator {
The `rev_iter` and `mut_rev_iter` methods on vectors just return an inverted
version of the standard immutable and mutable vector iterators.
-The `chain_`, `transform`, `filter`, `filter_map` and `peek` adaptors are
+The `chain`, `map`, `filter`, `filter_map` and `inspect` adaptors are
`DoubleEndedIterator` implementations if the underlying iterators are.
~~~
let xs = [1, 2, 3, 4];
let ys = [5, 6, 7, 8];
-let mut it = xs.iter().chain_(ys.iter()).transform(|&x| x * 2);
+let mut it = xs.iter().chain(ys.iter()).map(|&x| x * 2);
printfln!("%?", it.next()); // prints `Some(2)`
to the whole range. The `indexable` method retrieves the number of elements
accessible with the `idx` method.
-The `chain_` adaptor is an implementation of `RandomAccessIterator` if the
+The `chain` adaptor is an implementation of `RandomAccessIterator` if the
underlying iterators are.
~~~
let xs = [1, 2, 3, 4, 5];
let ys = ~[7, 9, 11];
-let mut it = xs.iter().chain_(ys.iter());
+let mut it = xs.iter().chain(ys.iter());
printfln!("%?", it.idx(0)); // prints `Some(&1)`
printfln!("%?", it.idx(5)); // prints `Some(&7)`
printfln!("%?", it.idx(7)); // prints `Some(&11)`
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
+#[fixed_stack_segment]
fn main() {
let x = unsafe { snappy_max_compressed_length(100) };
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
Rust's safe memory model.
+Finally, the `#[fixed_stack_segment]` annotation that appears on
+`main()` instructs the Rust compiler that when `main()` executes, it
+should request a "very large" stack segment. More details on
+stack management can be found in the following sections.
+
When declaring the argument types to a foreign function, the Rust compiler will not check if the
declaration is correct, so specifying it correctly is part of keeping the binding correct at
runtime.
the allocated memory. The length is less than or equal to the capacity.
~~~~ {.xfail-test}
+#[fixed_stack_segment]
+#[inline(never)]
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
unsafe {
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
signature.
+The `validate_compressed_buffer` wrapper is also annotated with two
+attributes `#[fixed_stack_segment]` and `#[inline(never)]`. The
+purpose of these attributes is to guarantee that there will be
+sufficient stack for the C function to execute. This is necessary
+because Rust, unlike C, does not assume that the stack is allocated in
+one continuous chunk. Instead, we rely on a *segmented stack* scheme,
+in which the stack grows and shrinks as necessary. C code, however,
+expects one large stack, and so callers of C functions must request a
+large stack segment to ensure that the C routine will not run off the
+end of the stack.
+
+The compiler includes a lint mode that will report an error if you
+call a C function without a `#[fixed_stack_segment]` attribute. More
+details on the lint mode are given in a later section.
+
+You may be wondering why we include a `#[inline(never)]` directive.
+This directive informs the compiler never to inline this function.
+While not strictly necessary, it is usually a good idea to use an
+`#[inline(never)]` directive in concert with `#[fixed_stack_segment]`.
+The reason is that if a fn annotated with `fixed_stack_segment` is
+inlined, then its caller also inherits the `fixed_stack_segment`
+annotation. This means that rather than requesting a large stack
+segment only for the duration of the call into C, the large stack
+segment would be used for the entire duration of the caller. This is
+not necessarily *bad* -- it can for example be more efficient,
+particularly if `validate_compressed_buffer()` is called multiple
+times in a row -- but it does work against the purpose of the
+segmented stack scheme, which is to keep stacks small and thus
+conserve address space.
+
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
allocated to hold the output too.
~~~~ {.xfail-test}
pub fn compress(src: &[u8]) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
~~~~ {.xfail-test}
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
For reference, the examples used here are also available as an [library on
GitHub](https://github.com/thestinger/rust-snappy).
+# Automatic wrappers
+
+Sometimes writing Rust wrappers can be quite tedious. For example, if
+function does not take any pointer arguments, often there is no need
+for translating types. In such cases, it is usually still a good idea
+to have a Rust wrapper so as to manage the segmented stacks, but you
+can take advantage of the (standard) `externfn!` macro to remove some
+of the tedium.
+
+In the initial section, we showed an extern block that added a call
+to a specific snappy API:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+#[link_args = "-lsnappy"]
+extern {
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+}
+
+#[fixed_stack_segment]
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+To avoid the need to create a wrapper fn for `snappy_max_compressed_length()`,
+and also to avoid the need to think about `#[fixed_stack_segment]`, we
+could simply use the `externfn!` macro instead, as shown here:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+externfn!(#[link_args = "-lsnappy"]
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+As you can see from the example, `externfn!` replaces the extern block
+entirely. After macro expansion, it will create something like this:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+// Automatically generated by
+// externfn!(#[link_args = "-lsnappy"]
+// fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t {
+ #[fixed_stack_segment]; #[inline(never)];
+ return snappy_max_compressed_length(source_length);
+
+ #[link_args = "-lsnappy"]
+ extern {
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+ }
+}
+
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+# Segmented stacks and the linter
+
+By default, whenever you invoke a non-Rust fn, the `cstack` lint will
+check that one of the following conditions holds:
+
+1. The call occurs inside of a fn that has been annotated with
+ `#[fixed_stack_segment]`;
+2. The call occurs inside of an `extern fn`;
+3. The call occurs within a stack closure created by some other
+ safe fn.
+
+All of these conditions ensure that you are running on a large stack
+segmented. However, they are sometimes too strict. If your application
+will be making many calls into C, it is often beneficial to promote
+the `#[fixed_stack_segment]` attribute higher up the call chain. For
+example, the Rust compiler actually labels main itself as requiring a
+`#[fixed_stack_segment]`. In such cases, the linter is just an
+annoyance, because all C calls that occur from within the Rust
+compiler are made on a large stack. Another situation where this
+frequently occurs is on a 64-bit architecture, where large stacks are
+the default. In cases, you can disable the linter by including a
+`#[allow(cstack)]` directive somewhere, which permits violations of
+the "cstack" rules given above (you can also use `#[warn(cstack)]` to
+convert the errors into warnings, if you prefer).
+
# Destructors
Foreign libraries often hand off ownership of resources to the calling code,
impl<T: Send> Unique<T> {
pub fn new(value: T) -> Unique<T> {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
assert!(!ptr::is_null(ptr));
#[unsafe_destructor]
impl<T: Send> Drop for Unique<T> {
fn drop(&self) {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let x = intrinsics::init(); // dummy value to swap in
// moving the object out is needed to call the destructor
fn signum(x: int) -> int {
if x < 0 { -1 }
else if x > 0 { 1 }
- else { return 0 }
+ else { 0 }
}
~~~~
rt/sync/rust_thread.cpp \
rt/rust_builtin.cpp \
rt/rust_run_program.cpp \
- rt/rust_env.cpp \
rt/rust_rng.cpp \
- rt/rust_stack.cpp \
rt/rust_upcall.cpp \
rt/rust_uv.cpp \
rt/rust_crate_map.cpp \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) $(BORROWCK) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
# Only build the compiler for host triples
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rust$$(X_$(4)): \
let env = env + target_env(lib_path, prog);
let mut proc = run::Process::new(prog, args, run::ProcessOptions {
- env: Some(env.slice(0, env.len())),
+ env: Some(env),
dir: None,
in_fd: None,
out_fd: None,
use util;
use util::logv;
+use std::cell::Cell;
use std::io;
use std::os;
use std::str;
+use std::task::{spawn_sched, SingleThreaded};
use std::vec;
use extra::test::MetricMap;
pub fn run(config: config, testfile: ~str) {
- let mut _mm = MetricMap::new();
- run_metrics(config, testfile, &mut _mm);
+ let config = Cell::new(config);
+ let testfile = Cell::new(testfile);
+ // FIXME #6436: Creating another thread to run the test because this
+ // is going to call waitpid. The new scheduler has some strange
+ // interaction between the blocking tasks and 'friend' schedulers
+ // that destroys parallelism if we let normal schedulers block.
+ // It should be possible to remove this spawn once std::run is
+ // rewritten to be non-blocking.
+ do spawn_sched(SingleThreaded) {
+ let config = config.take();
+ let testfile = testfile.take();
+ let mut _mm = MetricMap::new();
+ run_metrics(config, testfile, &mut _mm);
+ }
}
pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
#include <math.h>
#include <stdio.h>
-// must match core::ctypes
+// must match std::ctypes
#define C_FLT(x) (float)x
#define C_DBL(x) (double)x
# xfail-license
# This creates the tables used for distributions implemented using the
-# ziggurat algorithm in `core::rand::distributions;`. They are
+# ziggurat algorithm in `std::rand::distributions;`. They are
# (basically) the tables as used in the ZIGNOR variant (Doornik 2005).
# They are changed rarely, so the generated file should be checked in
# to git.
'path-statement[path statements with no effect]'
'missing-trait-doc[detects missing documentation for traits]'
'missing-struct-doc[detects missing documentation for structs]'
- 'ctypes[proper use of core::libc types in foreign modules]'
+ 'ctypes[proper use of std::libc types in foreign modules]'
"unused-mut[detect mut variables which don't need to be mutable]"
'unused-imports[imports that are never used]'
'heap-memory[use of any (~ type or @ type) heap memory]'
do 10.times {
let tmp = *num;
*num = -1;
- task::yield();
+ task::deschedule();
*num = tmp + 1;
}
c.send(());
do read_mode.read |state| {
// if writer mistakenly got in, make sure it mutates state
// before we assert on it
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
// make sure writer didn't get in.
assert!(*state);
}
}
#[test]
fn test_rw_write_cond_downgrade_read_race() {
- // Ideally the above test case would have yield statements in it that
+ // Ideally the above test case would have deschedule statements in it that
// helped to expose the race nearly 100% of the time... but adding
- // yields in the intuitively-right locations made it even less likely,
+ // deschedules in the intuitively-right locations made it even less likely,
// and I wasn't sure why :( . This is a mediocre "next best" option.
do 8.times { test_rw_write_cond_downgrade_read_race_helper() }
}
use std::libc;
fn malloc(n: size_t) -> CVec<u8> {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let mem = libc::malloc(n);
assert!(mem as int != 0);
- c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem))
+ return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
+ }
+
+ fn f(mem: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::free(mem) }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::num::One;
+use std::num::{One, Zero, CheckedAdd};
use std::vec::bytes::{MutableByteVector, copy_memory};
}
}
+/// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
+/// format.
+pub fn write_u32_le(dst: &mut[u8], input: u32) {
+ use std::cast::transmute;
+ use std::unstable::intrinsics::to_le32;
+ assert!(dst.len() == 4);
+ unsafe {
+ let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
+ *x = to_le32(input as i32);
+ }
+}
+
/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
use std::cast::transmute;
}
}
+/// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
+pub fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
+ use std::cast::transmute;
+ use std::unstable::intrinsics::to_le32;
+ assert!(dst.len() * 4 == input.len());
+ unsafe {
+ let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
+ let mut y: *i32 = transmute(input.unsafe_ref(0));
+ do dst.len().times() {
+ *x = to_le32(*y);
+ x = x.offset(1);
+ y = y.offset(1);
+ }
+ }
+}
+
-/// Returns true if adding the two parameters will result in integer overflow
-pub fn will_add_overflow<T: Int + Unsigned>(x: T, y: T) -> bool {
- // This doesn't handle negative values! Don't copy this code elsewhere without considering if
- // negative values are important to you!
- let max: T = Bounded::max_value();
- return x > max - y;
+trait ToBits {
+ /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
+ /// high-order value and the 2nd item is the low order value.
+ fn to_bits(self) -> (Self, Self);
}
-/// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned
-/// integer overflow.
-pub fn shift_add_check_overflow<T: Int + Unsigned + Clone>(x: T, mut y: T, shift: T) -> T {
- if y.leading_zeros() < shift {
- fail!("Could not add values - integer overflow.");
+impl ToBits for u64 {
+ fn to_bits(self) -> (u64, u64) {
+ return (self >> 61, self << 3);
}
- y = y << shift;
+}
- if will_add_overflow(x.clone(), y.clone()) {
- fail!("Could not add values - integer overflow.");
- }
+/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
+/// overflow.
+pub fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
+ let (new_high_bits, new_low_bits) = bytes.to_bits();
- return x + y;
-}
+ if new_high_bits > Zero::zero() {
+ fail!("Numeric overflow occured.")
+ }
-/// Shifts the second parameter and then adds it to the first, which is a tuple where the first
-/// element is the high order value. fails!() if there would be unsigned integer overflow.
-pub fn shift_add_check_overflow_tuple
- <T: Int + Unsigned + Clone>
- (x: (T, T), mut y: T, shift: T) -> (T, T) {
- if y.leading_zeros() < shift {
- fail!("Could not add values - integer overflow.");
+ match bits.checked_add(&new_low_bits) {
+ Some(x) => return x,
+ None => fail!("Numeric overflow occured.")
}
- y = y << shift;
+}
- match x {
- (hi, low) => {
- let one: T = One::one();
- if will_add_overflow(low.clone(), y.clone()) {
- if will_add_overflow(hi.clone(), one.clone()) {
- fail!("Could not add values - integer overflow.");
- } else {
- return (hi + one, low + y);
- }
+/// Adds the specified number of bytes to the bit count, which is a tuple where the first element is
+/// the high order value. fail!() if this would cause numeric overflow.
+pub fn add_bytes_to_bits_tuple
+ <T: Int + Unsigned + CheckedAdd + ToBits>
+ (bits: (T, T), bytes: T) -> (T, T) {
+ let (new_high_bits, new_low_bits) = bytes.to_bits();
+ let (hi, low) = bits;
+
+ // Add the low order value - if there is no overflow, then add the high order values
+ // If the addition of the low order values causes overflow, add one to the high order values
+ // before adding them.
+ match low.checked_add(&new_low_bits) {
+ Some(x) => {
+ if new_high_bits == Zero::zero() {
+ // This is the fast path - every other alternative will rarely occur in practice
+ // considering how large an input would need to be for those paths to be used.
+ return (hi, x);
} else {
- return (hi, low + y);
+ match hi.checked_add(&new_high_bits) {
+ Some(y) => return (y, x),
+ None => fail!("Numeric overflow occured.")
+ }
+ }
+ },
+ None => {
+ let one: T = One::one();
+ let z = match new_high_bits.checked_add(&one) {
+ Some(w) => w,
+ None => fail!("Numeric overflow occured.")
+ };
+ match hi.checked_add(&z) {
+ // This re-executes the addition that was already performed earlier when overflow
+ // occured, this time allowing the overflow to happen. Technically, this could be
+ // avoided by using the checked add intrinsic directly, but that involves using
+ // unsafe code and is not really worthwhile considering how infrequently code will
+ // run in practice. This is the reason that this function requires that the type T
+ // be Unsigned - overflow is not defined for Signed types. This function could be
+ // implemented for signed types as well if that were needed.
+ Some(y) => return (y, low + new_low_bits),
+ None => fail!("Numeric overflow occured.")
}
}
}
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
/// results in those bytes being marked as used by the buffer.
pub trait FixedBuffer {
- /// Input a vector of bytes. If the buffer becomes full, proccess it with the provided
+ /// Input a vector of bytes. If the buffer becomes full, process it with the provided
/// function and then clear the buffer.
fn input(&mut self, input: &[u8], func: &fn(&[u8]));
use std::rand::RngUtil;
use std::vec;
+ use cryptoutil::{add_bytes_to_bits, add_bytes_to_bits_tuple};
use digest::Digest;
/// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
assert!(expected == result_str);
}
+
+ // A normal addition - no overflow occurs
+ #[test]
+ fn test_add_bytes_to_bits_ok() {
+ assert!(add_bytes_to_bits::<u64>(100, 10) == 180);
+ }
+
+ // A simple failure case - adding 1 to the max value
+ #[test]
+ #[should_fail]
+ fn test_add_bytes_to_bits_overflow() {
+ add_bytes_to_bits::<u64>(Bounded::max_value(), 1);
+ }
+
+ // A normal addition - no overflow occurs (fast path)
+ #[test]
+ fn test_add_bytes_to_bits_tuple_ok() {
+ assert!(add_bytes_to_bits_tuple::<u64>((5, 100), 10) == (5, 180));
+ }
+
+ // The low order value overflows into the high order value
+ #[test]
+ fn test_add_bytes_to_bits_tuple_ok2() {
+ assert!(add_bytes_to_bits_tuple::<u64>((5, Bounded::max_value()), 1) == (6, 7));
+ }
+
+ // The value to add is too large to be converted into bits without overflowing its type
+ #[test]
+ fn test_add_bytes_to_bits_tuple_ok3() {
+ assert!(add_bytes_to_bits_tuple::<u64>((5, 0), 0x4000000000000001) == (7, 8));
+ }
+
+ // A simple failure case - adding 1 to the max value
+ #[test]
+ #[should_fail]
+ fn test_add_bytes_to_bits_tuple_overflow() {
+ add_bytes_to_bits_tuple::<u64>((Bounded::max_value(), Bounded::max_value()), 1);
+ }
+
+ // The value to add is too large to convert to bytes without overflowing its type, but the high
+ // order value from this conversion overflows when added to the existing high order value
+ #[test]
+ #[should_fail]
+ fn test_add_bytes_to_bits_tuple_overflow2() {
+ add_bytes_to_bits_tuple::<u64>((Bounded::max_value::<u64>() - 1, 0), 0x8000000000000000);
+ }
}
fn output_bits(&self) -> uint;
/**
- * Convenience functon that feeds a string into a digest
+ * Convenience function that feeds a string into a digest.
*
* # Arguments
*
- * * in The string to feed into the digest
+ * * `input` The string to feed into the digest
*/
fn input_str(&mut self, input: &str) {
self.input(input.as_bytes());
}
/**
- * Convenience functon that retrieves the result of a digest as a
+ * Convenience function that retrieves the result of a digest as a
* ~str in hexadecimal format.
*/
fn result_str(&mut self) -> ~str {
--- /dev/null
+// 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.
+
+use std::uint;
+
+use cryptoutil::{write_u32_le, read_u32v_le, FixedBuffer, FixedBuffer64, StandardPadding};
+use digest::Digest;
+
+
+// A structure that represents that state of a digest computation for the MD5 digest function
+struct Md5State {
+ s0: u32,
+ s1: u32,
+ s2: u32,
+ s3: u32
+}
+
+impl Md5State {
+ fn new() -> Md5State {
+ return Md5State {
+ s0: 0x67452301,
+ s1: 0xefcdab89,
+ s2: 0x98badcfe,
+ s3: 0x10325476
+ };
+ }
+
+ fn reset(&mut self) {
+ self.s0 = 0x67452301;
+ self.s1 = 0xefcdab89;
+ self.s2 = 0x98badcfe;
+ self.s3 = 0x10325476;
+ }
+
+ fn process_block(&mut self, input: &[u8]) {
+ fn f(u: u32, v: u32, w: u32) -> u32 {
+ return (u & v) | (!u & w);
+ }
+
+ fn g(u: u32, v: u32, w: u32) -> u32 {
+ return (u & w) | (v & !w);
+ }
+
+ fn h(u: u32, v: u32, w: u32) -> u32 {
+ return u ^ v ^ w;
+ }
+
+ fn i(u: u32, v: u32, w: u32) -> u32 {
+ return v ^ (u | !w);
+ }
+
+ fn rotate_left(x: u32, n: u32) -> u32 {
+ return (x << n) | (x >> (32 - n));
+ }
+
+ fn op_f(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + f(x, y, z) + m, s) + x;
+ }
+
+ fn op_g(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + g(x, y, z) + m, s) + x;
+ }
+
+ fn op_h(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + h(x, y, z) + m, s) + x;
+ }
+
+ fn op_i(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + i(x, y, z) + m, s) + x;
+ }
+
+ let mut a = self.s0;
+ let mut b = self.s1;
+ let mut c = self.s2;
+ let mut d = self.s3;
+
+ let mut data = [0u32, ..16];
+
+ read_u32v_le(data, input);
+
+ // round 1
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_f(a, b, c, d, data[i] + C1[i], 7);
+ d = op_f(d, a, b, c, data[i + 1] + C1[i + 1], 12);
+ c = op_f(c, d, a, b, data[i + 2] + C1[i + 2], 17);
+ b = op_f(b, c, d, a, data[i + 3] + C1[i + 3], 22);
+ true
+ };
+
+ // round 2
+ let mut t = 1;
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_g(a, b, c, d, data[t & 0x0f] + C2[i], 5);
+ d = op_g(d, a, b, c, data[(t + 5) & 0x0f] + C2[i + 1], 9);
+ c = op_g(c, d, a, b, data[(t + 10) & 0x0f] + C2[i + 2], 14);
+ b = op_g(b, c, d, a, data[(t + 15) & 0x0f] + C2[i + 3], 20);
+ t += 20;
+ true
+ };
+
+ // round 3
+ t = 5;
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_h(a, b, c, d, data[t & 0x0f] + C3[i], 4);
+ d = op_h(d, a, b, c, data[(t + 3) & 0x0f] + C3[i + 1], 11);
+ c = op_h(c, d, a, b, data[(t + 6) & 0x0f] + C3[i + 2], 16);
+ b = op_h(b, c, d, a, data[(t + 9) & 0x0f] + C3[i + 3], 23);
+ t += 12;
+ true
+ };
+
+ // round 4
+ t = 0;
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_i(a, b, c, d, data[t & 0x0f] + C4[i], 6);
+ d = op_i(d, a, b, c, data[(t + 7) & 0x0f] + C4[i + 1], 10);
+ c = op_i(c, d, a, b, data[(t + 14) & 0x0f] + C4[i + 2], 15);
+ b = op_i(b, c, d, a, data[(t + 21) & 0x0f] + C4[i + 3], 21);
+ t += 28;
+ true
+ };
+
+ self.s0 += a;
+ self.s1 += b;
+ self.s2 += c;
+ self.s3 += d;
+ }
+}
+
+// Round 1 constants
+static C1: [u32, ..16] = [
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
+];
+
+// Round 2 constants
+static C2: [u32, ..16] = [
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
+];
+
+// Round 3 constants
+static C3: [u32, ..16] = [
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
+];
+
+// Round 4 constants
+static C4: [u32, ..16] = [
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+];
+
+
+/// The MD5 Digest algorithm
+struct Md5 {
+ priv length_bytes: u64,
+ priv buffer: FixedBuffer64,
+ priv state: Md5State,
+ priv finished: bool,
+}
+
+impl Md5 {
+ /// Construct a new instance of the MD5 Digest.
+ pub fn new() -> Md5 {
+ return Md5 {
+ length_bytes: 0,
+ buffer: FixedBuffer64::new(),
+ state: Md5State::new(),
+ finished: false
+ }
+ }
+}
+
+impl Digest for Md5 {
+ fn input(&mut self, input: &[u8]) {
+ assert!(!self.finished);
+ // Unlike Sha1 and Sha2, the length value in MD5 is defined as the length of the message mod
+ // 2^64 - ie: integer overflow is OK.
+ self.length_bytes += input.len() as u64;
+ self.buffer.input(input, |d: &[u8]| { self.state.process_block(d); });
+ }
+
+ fn reset(&mut self) {
+ self.length_bytes = 0;
+ self.buffer.reset();
+ self.state.reset();
+ self.finished = false;
+ }
+
+ fn result(&mut self, out: &mut [u8]) {
+ if !self.finished {
+ self.buffer.standard_padding(8, |d: &[u8]| { self.state.process_block(d); });
+ write_u32_le(self.buffer.next(4), (self.length_bytes << 3) as u32);
+ write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
+ self.state.process_block(self.buffer.full_buffer());
+ self.finished = true;
+ }
+
+ write_u32_le(out.mut_slice(0, 4), self.state.s0);
+ write_u32_le(out.mut_slice(4, 8), self.state.s1);
+ write_u32_le(out.mut_slice(8, 12), self.state.s2);
+ write_u32_le(out.mut_slice(12, 16), self.state.s3);
+ }
+
+ fn output_bits(&self) -> uint { 128 }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use cryptoutil::test::test_digest_1million_random;
+ use digest::Digest;
+ use md5::Md5;
+
+
+ struct Test {
+ input: ~str,
+ output_str: ~str,
+ }
+
+ fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
+ // Test that it works when accepting the message all at once
+ for t in tests.iter() {
+ sh.input_str(t.input);
+
+ let out_str = sh.result_str();
+ assert!(out_str == t.output_str);
+
+ sh.reset();
+ }
+
+ // Test that it works when accepting the message in pieces
+ for t in tests.iter() {
+ let len = t.input.len();
+ let mut left = len;
+ while left > 0u {
+ let take = (left + 1u) / 2u;
+ sh.input_str(t.input.slice(len - left, take + len - left));
+ left = left - take;
+ }
+
+ let out_str = sh.result_str();
+ assert!(out_str == t.output_str);
+
+ sh.reset();
+ }
+ }
+
+ #[test]
+ fn test_md5() {
+ // Examples from wikipedia
+ let wikipedia_tests = ~[
+ Test {
+ input: ~"",
+ output_str: ~"d41d8cd98f00b204e9800998ecf8427e"
+ },
+ Test {
+ input: ~"The quick brown fox jumps over the lazy dog",
+ output_str: ~"9e107d9d372bb6826bd81d3542a419d6"
+ },
+ Test {
+ input: ~"The quick brown fox jumps over the lazy dog.",
+ output_str: ~"e4d909c290d0fb1ca068ffaddf22cbd0"
+ },
+ ];
+
+ let tests = wikipedia_tests;
+
+ let mut sh = Md5::new();
+
+ test_hash(&mut sh, tests);
+ }
+
+ #[test]
+ fn test_1million_random_md5() {
+ let mut sh = Md5::new();
+ test_digest_1million_random(
+ &mut sh,
+ 64,
+ "7707d6ae4e027c70eea2a935c2296f21");
+ }
+}
+
+
+#[cfg(test)]
+mod bench {
+ use extra::test::BenchHarness;
+
+ use md5::Md5;
+
+
+ #[bench]
+ pub fn md5_10(bh: & mut BenchHarness) {
+ let mut sh = Md5::new();
+ let bytes = [1u8, ..10];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn md5_1k(bh: & mut BenchHarness) {
+ let mut sh = Md5::new();
+ let bytes = [1u8, ..1024];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn md5_64k(bh: & mut BenchHarness) {
+ let mut sh = Md5::new();
+ let bytes = [1u8, ..65536];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+}
*/
-use cryptoutil::{write_u32_be, read_u32v_be, shift_add_check_overflow, FixedBuffer, FixedBuffer64,
+use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64,
StandardPadding};
use digest::Digest;
fn add_input(st: &mut Sha1, msg: &[u8]) {
assert!((!st.computed));
// Assumes that msg.len() can be converted to u64 without overflow
- st.length_bits = shift_add_check_overflow(st.length_bits, msg.len() as u64, 3);
+ st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); });
}
use std::uint;
-use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, shift_add_check_overflow,
- shift_add_check_overflow_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
+use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, add_bytes_to_bits,
+ add_bytes_to_bits_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
use digest::Digest;
fn input(&mut self, input: &[u8]) {
assert!(!self.finished)
// Assumes that input.len() can be converted to u64 without overflow
- self.length_bits = shift_add_check_overflow_tuple(self.length_bits, input.len() as u64, 3);
+ self.length_bits = add_bytes_to_bits_tuple(self.length_bits, input.len() as u64);
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
}
fn input(&mut self, input: &[u8]) {
assert!(!self.finished)
// Assumes that input.len() can be converted to u64 without overflow
- self.length_bits = shift_add_check_overflow(self.length_bits, input.len() as u64, 3);
+ self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64);
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
}
fn next_back(&mut self) -> Option<A> { self.list.pop_back() }
}
-impl<A, T: Iterator<A>> FromIterator<A, T> for DList<A> {
- fn from_iterator(iterator: &mut T) -> DList<A> {
+impl<A> FromIterator<A> for DList<A> {
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> DList<A> {
let mut ret = DList::new();
ret.extend(iterator);
ret
}
}
-impl<A, T: Iterator<A>> Extendable<A, T> for DList<A> {
- fn extend(&mut self, iterator: &mut T) {
+impl<A> Extendable<A> for DList<A> {
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T) {
for elt in *iterator { self.push_back(elt); }
}
}
}
}
}
-
priv bits: uint
}
-/// An iterface for casting C-like enum to uint and back.
+/// An interface for casting C-like enum to uint and back.
pub trait CLike {
/// Converts C-like enum to uint.
fn to_uint(&self) -> uint;
mod cryptoutil;
#[path="crypto/digest.rs"]
pub mod digest;
+#[path="crypto/md5.rs"]
+pub mod md5;
#[path="crypto/sha1.rs"]
pub mod sha1;
#[path="crypto/sha2.rs"]
pub mod fileinput;
pub mod flate;
pub mod hex;
+pub mod uuid;
+
#[cfg(unicode)]
mod unicode;
/**
Create a `FileInput` object from a vec of files. An empty
vec means lines are read from `stdin` (use `from_vec_raw` to stop
- this behaviour). Any occurence of `None` represents `stdin`.
+ this behaviour). Any occurrence of `None` represents `stdin`.
*/
pub fn from_vec(files: ~[Option<Path>]) -> FileInput {
FileInput::from_vec_raw(
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
}
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
This module is currently unsafe because it uses `Clone + Send` as a type
parameter bounds meaning POD (plain old data), but `Clone + Send` and
-POD are not equivelant.
+POD are not equivalent.
*/
pub mod pod {
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
-impl<T: Ord, Iter: Iterator<T>> FromIterator<T, Iter> for PriorityQueue<T> {
- fn from_iterator(iter: &mut Iter) -> PriorityQueue<T> {
+impl<T: Ord> FromIterator<T> for PriorityQueue<T> {
+ fn from_iterator<Iter: Iterator<T>>(iter: &mut Iter) -> PriorityQueue<T> {
let mut q = PriorityQueue::new();
q.extend(iter);
}
}
-impl<T: Ord, Iter: Iterator<T>> Extendable<T, Iter> for PriorityQueue<T> {
- fn extend(&mut self, iter: &mut Iter) {
+impl<T: Ord> Extendable<T> for PriorityQueue<T> {
+ fn extend<Iter: Iterator<T>>(&mut self, iter: &mut Iter) {
let (lower, _) = iter.size_hint();
let len = self.capacity();
}
}
-impl<A, T: Iterator<A>> FromIterator<A, T> for RingBuf<A> {
- fn from_iterator(iterator: &mut T) -> RingBuf<A> {
+impl<A> FromIterator<A> for RingBuf<A> {
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> RingBuf<A> {
let (lower, _) = iterator.size_hint();
let mut deq = RingBuf::with_capacity(lower);
deq.extend(iterator);
}
}
-impl<A, T: Iterator<A>> Extendable<A, T> for RingBuf<A> {
- fn extend(&mut self, iterator: &mut T) {
+impl<A> Extendable<A> for RingBuf<A> {
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T) {
for elt in *iterator {
self.push_back(elt);
}
pub mod rustrt {
use std::libc::{c_char, c_int};
- extern {
- pub fn linenoise(prompt: *c_char) -> *c_char;
- pub fn linenoiseHistoryAdd(line: *c_char) -> c_int;
- pub fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
- pub fn linenoiseHistorySave(file: *c_char) -> c_int;
- pub fn linenoiseHistoryLoad(file: *c_char) -> c_int;
- pub fn linenoiseSetCompletionCallback(callback: *u8);
- pub fn linenoiseAddCompletion(completions: *(), line: *c_char);
+ #[cfg(stage0)]
+ mod macro_hack {
+ #[macro_escape];
+ macro_rules! externfn(
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+ )
}
+
+ externfn!(fn linenoise(prompt: *c_char) -> *c_char)
+ externfn!(fn linenoiseHistoryAdd(line: *c_char) -> c_int)
+ externfn!(fn linenoiseHistorySetMaxLen(len: c_int) -> c_int)
+ externfn!(fn linenoiseHistorySave(file: *c_char) -> c_int)
+ externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
+ externfn!(fn linenoiseSetCompletionCallback(callback: *u8))
+ externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
}
/// Add a line to history
pub unsafe fn add_history(line: &str) -> bool {
- do line.to_c_str().with_ref |buf| {
+ do line.with_c_str |buf| {
rustrt::linenoiseHistoryAdd(buf) == 1 as c_int
}
}
/// Save line history to a file
pub unsafe fn save_history(file: &str) -> bool {
- do file.to_c_str().with_ref |buf| {
+ do file.with_c_str |buf| {
rustrt::linenoiseHistorySave(buf) == 1 as c_int
}
}
/// Load line history from a file
pub unsafe fn load_history(file: &str) -> bool {
- do file.to_c_str().with_ref |buf| {
+ do file.with_c_str |buf| {
rustrt::linenoiseHistoryLoad(buf) == 1 as c_int
}
}
/// Print out a prompt and then wait for input and return it
pub unsafe fn read(prompt: &str) -> Option<~str> {
- do prompt.to_c_str().with_ref |buf| {
+ do prompt.with_c_str |buf| {
let line = rustrt::linenoise(buf);
if line.is_null() { None }
unsafe {
do cb(str::raw::from_c_str(line)) |suggestion| {
- do suggestion.to_c_str().with_ref |buf| {
+ do suggestion.with_c_str |buf| {
rustrt::linenoiseAddCompletion(completions, buf);
}
}
-}
+ }
}
}
#[cfg(test)]
mod test_qsort {
-
use sort::*;
- use std::vec;
-
fn check_sort(v1: &mut [int], v2: &mut [int]) {
let len = v1.len();
fn leual(a: &int, b: &int) -> bool { *a <= *b }
let immut_names = names;
- let pairs = vec::zip_slice(expected, immut_names);
- for p in pairs.iter() {
- let (a, b) = *p;
+ for (&a, &b) in expected.iter().zip(immut_names.iter()) {
debug!("%d %d", a, b);
assert_eq!(a, b);
}
w.write_str(histr);
}
-/// Returns a HashMap with the number of occurences of every element in the
+/// Returns a HashMap with the number of occurrences of every element in the
/// sequence that the iterator exposes.
pub fn freq_count<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
let mut map = hashmap::HashMap::new::<U, uint>();
}
}
// Uncomment if you wish to test for sem races. Not valgrind-friendly.
- /* do 1000.times { task::yield(); } */
+ /* do 1000.times { task::deschedule(); } */
// Need to wait outside the exclusive.
if waiter_nobe.is_some() {
let _ = waiter_nobe.unwrap().recv();
}
}
- // If yield checks start getting inserted anywhere, we can be
+ // If deschedule checks start getting inserted anywhere, we can be
// killed before or after enqueueing. Deciding whether to
// unkillably reacquire the lock needs to happen atomically
// wrt enqueuing.
let s2 = ~s.clone();
do task::spawn || {
do s2.access {
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
}
}
do s.access {
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
}
}
#[test]
s2.acquire();
c.send(());
}
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
s.release();
let _ = p.recv();
let s = ~Semaphore::new(0);
let s2 = ~s.clone();
do task::spawn || {
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
s2.release();
let _ = p.recv();
}
c.send(());
}
let _ = p.recv(); // wait for child to come alive
- do 5.times { task::yield(); } // let the child contend
+ do 5.times { task::deschedule(); } // let the child contend
}
let _ = p.recv(); // wait for child to be done
}
do n.times {
do m.lock {
let oldval = *sharedstate;
- task::yield();
+ task::deschedule();
*sharedstate = oldval + 1;
}
}
let (p,c) = comm::stream();
do task::spawn || { // linked
let _ = p.recv(); // wait for sibling to get in the mutex
- task::yield();
+ task::deschedule();
fail!();
}
do m2.lock_cond |cond| {
do n.times {
do lock_rwlock_in_mode(x, mode) {
let oldval = *sharedstate;
- task::yield();
+ task::deschedule();
*sharedstate = oldval + 1;
}
}
/// If the color is a bright color, but the terminal only supports 8 colors,
/// the corresponding normal color will be used instead.
///
- /// Rturns true if the color was set, false otherwise.
+ /// Returns true if the color was set, false otherwise.
pub fn bg(&self, color: color::Color) -> bool {
let color = self.dim_if_necessary(color);
if self.num_colors > color {
}
fn usage(binary: &str, helpstr: &str) -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
let message = fmt!("Usage: %s [OPTIONS] [FILTER]", binary);
println(groups::usage(message, optgroups()));
println("");
use std::either;
use std::comm::{stream, SharedChan};
- use std::vec;
use tempfile;
use std::os;
~"test::parse_ignored_flag",
~"test::sort_tests"];
- let pairs = vec::zip(expected, filtered);
-
- for p in pairs.iter() {
- match *p {
- (ref a, ref b) => {
- assert!(*a == b.desc.name.to_str());
- }
- }
+ for (a, b) in expected.iter().zip(filtered.iter()) {
+ assert!(*a == b.desc.name.to_str());
}
}
}
/// A record specifying a time value in seconds and nanoseconds.
-#[deriving(Eq, Encodable, Decodable)]
+#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Timespec { sec: i64, nsec: i32 }
/*
* nanoseconds since 1970-01-01T00:00:00Z.
*/
pub fn get_time() -> Timespec {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut sec = 0i64;
let mut nsec = 0i32;
* in nanoseconds since an unspecified epoch.
*/
pub fn precise_time_ns() -> u64 {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut ns = 0u64;
rustrt::precise_time_ns(&mut ns);
}
pub fn tzset() {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
rustrt::rust_tzset();
}
}
-#[deriving(Eq, Encodable, Decodable)]
+#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Tm {
tm_sec: i32, // seconds after the minute ~[0-60]
tm_min: i32, // minutes after the hour ~[0-59]
/// Returns the specified time in UTC
pub fn at_utc(clock: Timespec) -> Tm {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
/// Returns the specified time in the local timezone
pub fn at(clock: Timespec) -> Tm {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
impl Tm {
/// Convert time to the seconds from January 1, 1970
pub fn to_timespec(&self) -> Timespec {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let sec = match self.tm_gmtoff {
0_i32 => rustrt::rust_timegm(self),
};
}
-impl<K: TotalOrd, V, T: Iterator<(K, V)>> FromIterator<(K, V), T> for TreeMap<K, V> {
- fn from_iterator(iter: &mut T) -> TreeMap<K, V> {
+impl<K: TotalOrd, V> FromIterator<(K, V)> for TreeMap<K, V> {
+ fn from_iterator<T: Iterator<(K, V)>>(iter: &mut T) -> TreeMap<K, V> {
let mut map = TreeMap::new();
map.extend(iter);
map
}
}
-impl<K: TotalOrd, V, T: Iterator<(K, V)>> Extendable<(K, V), T> for TreeMap<K, V> {
+impl<K: TotalOrd, V> Extendable<(K, V)> for TreeMap<K, V> {
#[inline]
- fn extend(&mut self, iter: &mut T) {
+ fn extend<T: Iterator<(K, V)>>(&mut self, iter: &mut T) {
for (k, v) in *iter {
self.insert(k, v);
}
}
}
-impl<T: TotalOrd, Iter: Iterator<T>> FromIterator<T, Iter> for TreeSet<T> {
- fn from_iterator(iter: &mut Iter) -> TreeSet<T> {
+impl<T: TotalOrd> FromIterator<T> for TreeSet<T> {
+ fn from_iterator<Iter: Iterator<T>>(iter: &mut Iter) -> TreeSet<T> {
let mut set = TreeSet::new();
set.extend(iter);
set
}
}
-impl<T: TotalOrd, Iter: Iterator<T>> Extendable<T, Iter> for TreeSet<T> {
+impl<T: TotalOrd> Extendable<T> for TreeSet<T> {
#[inline]
- fn extend(&mut self, iter: &mut Iter) {
+ fn extend<Iter: Iterator<T>>(&mut self, iter: &mut Iter) {
for elem in *iter {
self.insert(elem);
}
--- /dev/null
+// 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.
+
+/*!
+Generate and parse UUIDs
+
+Provides support for Universally Unique Identifiers (UUIDs). A UUID is a
+unique 128-bit number, stored as 16 octets. UUIDs are used to assign unique
+identifiers to entities without requiring a central allocating authority.
+
+They are particularly useful in distributed systems, though can be used in
+disparate areas, such as databases and network protocols. Typically a UUID is
+displayed in a readable string form as a sequence of hexadecimals digits,
+separated into groups by hyphens.
+
+The uniqueness property is not strictly guaranteed, however for all practical
+purposes, it can be assumed that an unintentional collision would be extremely
+unlikely.
+
+# Examples
+
+To create a new random (V4) UUID and print it out in hexadecimal form:
+
+~~~ {.rust}
+extern mod extra;
+use extra::uuid::Uuid;
+
+fn main() {
+ let uuid1 = Uuid::new_v4();
+ println(uuid1.to_str());
+}
+~~~
+
+# Strings
+
+Examples of string representations:
+
+* simple: `936DA01F9ABD4d9d80C702AF85C822A8`
+* hyphenated: `550e8400-e29b-41d4-a716-446655440000`
+* urn: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
+
+# References
+
+* [Wikipedia: Universally Unique Identifier](
+ http://en.wikipedia.org/wiki/Universally_unique_identifier)
+* [RFC4122: A Universally Unique IDentifier (UUID) URN Namespace](
+ http://tools.ietf.org/html/rfc4122)
+
+*/
+
+use std::str;
+use std::vec;
+use std::num::{FromStrRadix, Zero};
+use std::char::Char;
+use std::container::Container;
+use std::to_str::ToStr;
+use std::rand;
+use std::rand::RngUtil;
+use std::cmp::Eq;
+use std::cast::{transmute,transmute_copy};
+
+/// A 128-bit (16 byte) buffer containing the ID
+pub type UuidBytes = [u8, ..16];
+
+/// The version of the UUID, denoting the generating algorithm
+#[deriving(Eq)]
+pub enum UuidVersion {
+ /// Version 1: MAC address
+ Version1Mac = 1,
+ /// Version 2: DCE Security
+ Version2Dce = 2,
+ /// Version 3: MD5 hash
+ Version3Md5 = 3,
+ /// Version 4: Random
+ Version4Random = 4,
+ /// Version 5: SHA-1 hash
+ Version5Sha1 = 5,
+}
+
+/// The reserved variants of UUIDs
+#[deriving(Eq)]
+pub enum UuidVariant {
+ /// Reserved by the NCS for backward compatability
+ VariantNCS,
+ /// As described in the RFC4122 Specification (default)
+ VariantRFC4122,
+ /// Resreved by Microsoft for backward compatability
+ VariantMicrosoft,
+ /// Reserved for future expansion
+ VariantFuture,
+}
+
+/// A Universally Unique Identifier (UUID)
+pub struct Uuid {
+ /// The 128-bit number stored in 16 bytes
+ bytes: UuidBytes
+}
+
+/// A UUID stored as fields (identical to UUID, used only for conversions)
+struct UuidFields {
+ /// First field, 32-bit word
+ data1: u32,
+ /// Second field, 16-bit short
+ data2: u16,
+ /// Third field, 16-bit short
+ data3: u16,
+ /// Fourth field, 8 bytes
+ data4: [u8, ..8]
+}
+
+/// Error details for string parsing failures
+pub enum ParseError {
+ ErrorInvalidLength(uint),
+ ErrorInvalidCharacter(char, uint),
+ ErrorInvalidGroups(uint),
+ ErrorInvalidGroupLength(uint, uint, uint),
+}
+
+/// Converts a ParseError to a string
+impl ToStr for ParseError {
+ #[inline]
+ fn to_str(&self) -> ~str {
+ match *self {
+ ErrorInvalidLength(found) =>
+ fmt!("Invalid length; expecting 32, 36 or 45 chars, found %u",
+ found),
+ ErrorInvalidCharacter(found, pos) =>
+ fmt!("Invalid character; found `%c` (0x%02x) at offset %u",
+ found, found as uint, pos),
+ ErrorInvalidGroups(found) =>
+ fmt!("Malformed; wrong number of groups: expected 1 or 5, found %u",
+ found),
+ ErrorInvalidGroupLength(group, found, expecting) =>
+ fmt!("Malformed; length of group %u was %u, expecting %u",
+ group, found, expecting),
+ }
+ }
+}
+
+// Length of each hyphenated group in hex digits
+static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u];
+
+/// UUID support
+impl Uuid {
+
+ /// Returns a nil or empty UUID (containing all zeroes)
+ pub fn new_nil() -> Uuid {
+ let uuid = Uuid{ bytes: [0, .. 16] };
+ uuid
+ }
+
+ /// Create a new UUID of the specified version
+ pub fn new(v: UuidVersion) -> Option<Uuid> {
+ match v {
+ Version4Random => Some(Uuid::new_v4()),
+ _ => None
+ }
+ }
+
+ /// Creates a new random UUID
+ ///
+ /// Uses the `rand` module's default RNG task as the source
+ /// of random numbers. Use the rand::Rand trait to supply
+ /// a custom generator if required.
+ pub fn new_v4() -> Uuid {
+ let ub = rand::task_rng().gen_bytes(16);
+ let mut uuid = Uuid{ bytes: [0, .. 16] };
+ vec::bytes::copy_memory(uuid.bytes, ub, 16);
+ uuid.set_variant(VariantRFC4122);
+ uuid.set_version(Version4Random);
+ uuid
+ }
+
+ /// Creates a UUID using the supplied field values
+ ///
+ /// # Arguments
+ /// * `d1` A 32-bit word
+ /// * `d2` A 16-bit word
+ /// * `d3` A 16-bit word
+ /// * `d4` Array of 8 octets
+ pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid {
+ use std::unstable::intrinsics::{to_be16, to_be32};
+
+ // First construct a temporary field-based struct
+ let mut fields = UuidFields {
+ data1: 0,
+ data2: 0,
+ data3: 0,
+ data4: [0, ..8]
+ };
+
+ fields.data1 = to_be32(d1 as i32) as u32;
+ fields.data2 = to_be16(d2 as i16) as u16;
+ fields.data3 = to_be16(d3 as i16) as u16;
+ vec::bytes::copy_memory(fields.data4, d4, 8);
+
+ unsafe {
+ transmute(fields)
+ }
+ }
+
+ /// Creates a UUID using the supplied bytes
+ ///
+ /// # Arguments
+ /// * `b` An array or slice of 16 bytes
+ pub fn from_bytes(b: &[u8]) -> Option<Uuid> {
+ if b.len() != 16 {
+ return None
+ }
+
+ let mut uuid = Uuid{ bytes: [0, .. 16] };
+ unsafe {
+ vec::raw::copy_memory(uuid.bytes, b, 16);
+ }
+ Some(uuid)
+ }
+
+ /// Specifies the variant of the UUID structure
+ fn set_variant(&mut self, v: UuidVariant) {
+ // Octet 8 contains the variant in the most significant 3 bits
+ match v {
+ VariantNCS => // b0xx...
+ self.bytes[8] = self.bytes[8] & 0x7f,
+ VariantRFC4122 => // b10x...
+ self.bytes[8] = (self.bytes[8] & 0x3f) | 0x80,
+ VariantMicrosoft => // b110...
+ self.bytes[8] = (self.bytes[8] & 0x1f) | 0xc0,
+ VariantFuture => // b111...
+ self.bytes[8] = (self.bytes[8] & 0x1f) | 0xe0,
+ }
+ }
+
+ /// Returns the variant of the UUID structure
+ ///
+ /// This determines the interpretation of the structure of the UUID.
+ /// Currently only the RFC4122 variant is generated by this module.
+ ///
+ /// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1)
+ pub fn get_variant(&self) -> Option<UuidVariant> {
+ if self.bytes[8] & 0x80 == 0x00 {
+ Some(VariantNCS)
+ } else if self.bytes[8] & 0xc0 == 0x80 {
+ Some(VariantRFC4122)
+ } else if self.bytes[8] & 0xe0 == 0xc0 {
+ Some(VariantMicrosoft)
+ } else if self.bytes[8] & 0xe0 == 0xe0 {
+ Some(VariantFuture)
+ } else {
+ None
+ }
+ }
+
+ /// Specifies the version number of the UUID
+ fn set_version(&mut self, v: UuidVersion) {
+ self.bytes[6] = (self.bytes[6] & 0xF) | ((v as u8) << 4);
+ }
+
+ /// Returns the version number of the UUID
+ ///
+ /// This represents the algorithm used to generate the contents.
+ ///
+ /// Currently only the Random (V4) algorithm is supported by this
+ /// module. There are security and privacy implications for using
+ /// older versions - see [Wikipedia: Universally Unique Identifier](
+ /// http://en.wikipedia.org/wiki/Universally_unique_identifier) for
+ /// details.
+ ///
+ /// * [Version Reference](http://tools.ietf.org/html/rfc4122#section-4.1.3)
+ pub fn get_version_num(&self) -> uint {
+ (self.bytes[6] >> 4) as uint
+ }
+
+ /// Returns the version of the UUID
+ ///
+ /// This represents the algorithm used to generate the contents
+ pub fn get_version(&self) -> Option<UuidVersion> {
+ let v = (self.bytes[6] >> 4);
+ match v {
+ 1 => Some(Version1Mac),
+ 2 => Some(Version2Dce),
+ 3 => Some(Version3Md5),
+ 4 => Some(Version4Random),
+ 5 => Some(Version5Sha1),
+ _ => None
+ }
+ }
+
+ /// Return an array of 16 octets containing the UUID data
+ pub fn to_bytes<'a>(&'a self) -> &'a [u8] {
+ self.bytes.as_slice()
+ }
+
+ /// Returns the UUID as a string of 16 hexadecimal digits
+ ///
+ /// Example: `936DA01F9ABD4d9d80C702AF85C822A8`
+ pub fn to_simple_str(&self) -> ~str {
+ let mut s: ~[u8] = vec::from_elem(32, 0u8);
+ for i in range(0u, 16u) {
+ let digit = fmt!("%02x", self.bytes[i] as uint);
+ s[i*2+0] = digit[0];
+ s[i*2+1] = digit[1];
+ }
+ str::from_bytes(s)
+ }
+
+ /// Returns a string of hexadecimal digits, separated into groups with a hypen
+ ///
+ /// Example: `550e8400-e29b-41d4-a716-446655440000`
+ pub fn to_hyphenated_str(&self) -> ~str {
+ use std::unstable::intrinsics::{to_be16, to_be32};
+ // Convert to field-based struct as it matches groups in output.
+ // Ensure fields are in network byte order, as per RFC.
+ let mut uf: UuidFields;
+ unsafe {
+ uf = transmute_copy(&self.bytes);
+ }
+ uf.data1 = to_be32(uf.data1 as i32) as u32;
+ uf.data2 = to_be16(uf.data2 as i16) as u16;
+ uf.data3 = to_be16(uf.data3 as i16) as u16;
+ let s = fmt!("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uf.data1 as uint,
+ uf.data2 as uint, uf.data3 as uint,
+ uf.data4[0] as uint, uf.data4[1] as uint,
+ uf.data4[2] as uint, uf.data4[3] as uint, uf.data4[4] as uint,
+ uf.data4[5] as uint, uf.data4[6] as uint, uf.data4[7] as uint);
+ s
+ }
+
+ /// Returns the UUID formatted as a full URN string
+ ///
+ /// This is the same as the hyphenated format, but with the "urn:uuid:" prefix.
+ ///
+ /// Example: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
+ pub fn to_urn_str(&self) -> ~str {
+ "urn:uuid:" + self.to_hyphenated_str()
+ }
+
+ /// Parses a UUID from a string of hexadecimal digits with optional hyphens
+ ///
+ /// Any of the formats generated by this module (simple, hyphenated, urn) are
+ /// supported by this parsing function.
+ pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
+
+ let mut us = us.clone();
+ let orig_len = us.len();
+
+ // Ensure length is valid for any of the supported formats
+ if orig_len != 32 && orig_len != 36 && orig_len != 45 {
+ return Err(ErrorInvalidLength(orig_len));
+ }
+
+ // Strip off URN prefix if present
+ if us.starts_with("urn:uuid:") {
+ us = us.slice(9, orig_len);
+ }
+
+ // Make sure all chars are either hex digits or hyphen
+ for (i, c) in us.iter().enumerate() {
+ match c {
+ '0'..'9' | 'A'..'F' | 'a'..'f' | '-' => {},
+ _ => return Err(ErrorInvalidCharacter(c, i)),
+ }
+ }
+
+ // Split string up by hyphens into groups
+ let hex_groups: ~[&str] = us.split_str_iter("-").collect();
+
+ // Get the length of each group
+ let group_lens: ~[uint] = hex_groups.iter().map(|&v| v.len()).collect();
+
+ // Ensure the group lengths are valid
+ match group_lens.len() {
+ // Single group, no hyphens
+ 1 => {
+ if group_lens[0] != 32 {
+ return Err(ErrorInvalidLength(group_lens[0]));
+ }
+ },
+ // Five groups, hyphens in between each
+ 5 => {
+ // Ensure each group length matches the expected
+ for (i, (&gl, &expected)) in
+ group_lens.iter().zip(UuidGroupLens.iter()).enumerate() {
+ if gl != expected {
+ return Err(ErrorInvalidGroupLength(i, gl, expected))
+ }
+ }
+ },
+ _ => {
+ return Err(ErrorInvalidGroups(group_lens.len()));
+ }
+ }
+
+ // Normalise into one long hex string
+ let vs = hex_groups.concat();
+
+ // At this point, we know we have a valid hex string, without hyphens
+ assert!(vs.len() == 32);
+ assert!(vs.iter().all(|c| c.is_digit_radix(16)));
+
+ // Allocate output UUID buffer
+ let mut ub = [0u8, ..16];
+
+ // Extract each hex digit from the string
+ for i in range(0u, 16u) {
+ ub[i] = FromStrRadix::from_str_radix(vs.slice(i*2, (i+1)*2), 16).unwrap();
+ }
+
+ Ok(Uuid::from_bytes(ub).unwrap())
+ }
+}
+
+impl Zero for Uuid {
+ /// Returns the nil UUID, which is all zeroes
+ fn zero() -> Uuid {
+ Uuid::new_nil()
+ }
+
+ /// Tests if the UUID is nil or all zeroes
+ fn is_zero(&self) -> bool {
+ return self.bytes.iter().all(|&b| b == 0);
+ }
+}
+
+impl Clone for Uuid {
+ /// Returns a copy of the UUID
+ fn clone(&self) -> Uuid {
+ let mut clone = Uuid{ bytes: [0, .. 16] };
+ vec::bytes::copy_memory(clone.bytes, self.bytes, 16);
+ clone
+ }
+}
+
+impl FromStr for Uuid {
+ /// Parse a hex string and interpret as a UUID
+ ///
+ /// Accepted formats are a sequence of 32 hexadecimal characters,
+ /// with or without hypens (grouped as 8, 4, 4, 4, 12).
+ fn from_str(us: &str) -> Option<Uuid> {
+ let result = Uuid::parse_string(us);
+ match result {
+ Ok(u) => Some(u),
+ Err(_) => None
+ }
+ }
+}
+
+/// Convert the UUID to a hexadecimal-based string representation
+impl ToStr for Uuid {
+ fn to_str(&self) -> ~str {
+ self.to_simple_str()
+ }
+}
+
+/// Test two UUIDs for equality
+///
+/// UUIDs are equal only when they are byte-for-byte identical
+impl Eq for Uuid {
+ fn eq(&self, other: &Uuid) -> bool {
+ self.bytes == other.bytes
+ }
+}
+
+/// Test two UUIDs for equality
+///
+/// UUIDs are equal only when they are byte-for-byte identical
+impl TotalEq for Uuid {
+ fn equals(&self, other: &Uuid) -> bool {
+ self.bytes == other.bytes
+ }
+}
+
+/// Generates a random instance of UUID (V4 conformant)
+impl rand::Rand for Uuid {
+ #[inline]
+ fn rand<R: rand::Rng>(rng: &mut R) -> Uuid {
+ let ub = rng.gen_bytes(16);
+ let mut uuid = Uuid{ bytes: [0, .. 16] };
+ vec::bytes::copy_memory(uuid.bytes, ub, 16);
+ uuid.set_variant(VariantRFC4122);
+ uuid.set_version(Version4Random);
+ uuid
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::str;
+ use std::rand;
+ use std::num::Zero;
+
+ #[test]
+ fn test_new_nil() {
+ let nil = Uuid::new_nil();
+ let nb = nil.to_bytes();
+
+ assert!(nb.iter().all(|&b| b == 0));
+ }
+
+ #[test]
+ fn test_zero() {
+ let uz: Uuid = Zero::zero();
+ let nz = Uuid::new_v4();
+
+ assert!(uz.is_zero());
+ assert!(! nz.is_zero());
+ }
+
+ #[test]
+ fn test_new() {
+ // Supported
+ let uuid1 = Uuid::new(Version4Random).unwrap();
+ let s = uuid1.to_simple_str();
+
+ assert!(s.len() == 32);
+ assert!(uuid1.get_version().unwrap() == Version4Random);
+
+ // Test unsupported versions
+ assert!(Uuid::new(Version1Mac) == None);
+ assert!(Uuid::new(Version2Dce) == None);
+ assert!(Uuid::new(Version3Md5) == None);
+ assert!(Uuid::new(Version5Sha1) == None);
+ }
+
+ #[test]
+ fn test_new_v4() {
+ let uuid1 = Uuid::new_v4();
+
+ assert!(uuid1.get_version().unwrap() == Version4Random);
+ assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
+ }
+
+ #[test]
+ fn test_get_version() {
+ let uuid1 = Uuid::new_v4();
+
+ assert!(uuid1.get_version().unwrap() == Version4Random);
+ assert!(uuid1.get_version_num() == 4);
+ }
+
+ #[test]
+ fn test_get_variant() {
+ let uuid1 = Uuid::new_v4();
+ let uuid2 = Uuid::parse_string("550e8400-e29b-41d4-a716-446655440000").unwrap();
+ let uuid3 = Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
+ let uuid4 = Uuid::parse_string("936DA01F9ABD4d9dC0C702AF85C822A8").unwrap();
+ let uuid5 = Uuid::parse_string("F9168C5E-CEB2-4faa-D6BF-329BF39FA1E4").unwrap();
+ let uuid6 = Uuid::parse_string("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap();
+
+ assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
+ assert!(uuid2.get_variant().unwrap() == VariantRFC4122);
+ assert!(uuid3.get_variant().unwrap() == VariantRFC4122);
+ assert!(uuid4.get_variant().unwrap() == VariantMicrosoft);
+ assert!(uuid5.get_variant().unwrap() == VariantMicrosoft);
+ assert!(uuid6.get_variant().unwrap() == VariantNCS);
+ }
+
+ #[test]
+ fn test_parse_uuid_v4() {
+
+ // Invalid
+ assert!(Uuid::parse_string("").is_err());
+ assert!(Uuid::parse_string("!").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("01020304-1112-2122-3132-41424344").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c88").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0cg8").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426%9247bb680e5fe0c8").is_err());
+
+ // Valid
+ assert!(Uuid::parse_string("00000000000000000000000000000000").is_ok());
+ assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
+ assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c8").is_ok());
+ assert!(Uuid::parse_string("01020304-1112-2122-3132-414243444546").is_ok());
+ assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
+
+ // Nil
+ let nil = Uuid::new_nil();
+ assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
+ assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
+
+ // Round-trip
+ let uuid_orig = Uuid::new_v4();
+ let orig_str = uuid_orig.to_str();
+ let uuid_out = Uuid::parse_string(orig_str).unwrap();
+ assert!(uuid_orig == uuid_out);
+
+ // Test error reporting
+ let e = Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").unwrap_err();
+ assert!(match(e){ ErrorInvalidLength(n) => n==31, _ => false });
+
+ let e = Uuid::parse_string("67e550X410b1426f9247bb680e5fe0cd").unwrap_err();
+ assert!(match(e){ ErrorInvalidCharacter(c, n) => c=='X' && n==6, _ => false });
+
+ let e = Uuid::parse_string("67e550-4105b1426f9247bb680e5fe0c").unwrap_err();
+ assert!(match(e){ ErrorInvalidGroups(n) => n==2, _ => false });
+
+ let e = Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4").unwrap_err();
+ assert!(match(e){ ErrorInvalidGroupLength(g, n, e) => g==3 && n==5 && e==4, _ => false });
+ }
+
+ #[test]
+ fn test_to_simple_str() {
+ let uuid1 = Uuid::new_v4();
+ let s = uuid1.to_simple_str();
+
+ assert!(s.len() == 32);
+ assert!(s.iter().all(|c| c.is_digit_radix(16)));
+ }
+
+ #[test]
+ fn test_to_str() {
+ let uuid1 = Uuid::new_v4();
+ let s = uuid1.to_str();
+
+ assert!(s.len() == 32);
+ assert!(s.iter().all(|c| c.is_digit_radix(16)));
+ }
+
+ #[test]
+ fn test_to_hyphenated_str() {
+ let uuid1 = Uuid::new_v4();
+ let s = uuid1.to_hyphenated_str();
+
+ assert!(s.len() == 36);
+ assert!(s.iter().all(|c| c.is_digit_radix(16) || c == '-'));
+ }
+
+ #[test]
+ fn test_to_urn_str() {
+ let uuid1 = Uuid::new_v4();
+ let ss = uuid1.to_urn_str();
+ let s = ss.slice(9, ss.len());
+
+ assert!(ss.starts_with("urn:uuid:"));
+ assert!(s.len() == 36);
+ assert!(s.iter().all(|c| c.is_digit_radix(16) || c == '-'));
+ }
+
+ #[test]
+ fn test_to_str_matching() {
+ let uuid1 = Uuid::new_v4();
+
+ let hs = uuid1.to_hyphenated_str();
+ let ss = uuid1.to_str();
+
+ let hsn = str::from_chars(hs.iter().filter(|&c| c != '-').collect::<~[char]>());
+
+ assert!(hsn == ss);
+ }
+
+ #[test]
+ fn test_string_roundtrip() {
+ let uuid = Uuid::new_v4();
+
+ let hs = uuid.to_hyphenated_str();
+ let uuid_hs = Uuid::parse_string(hs).unwrap();
+ assert!(uuid_hs == uuid);
+
+ let ss = uuid.to_str();
+ let uuid_ss = Uuid::parse_string(ss).unwrap();
+ assert!(uuid_ss == uuid);
+ }
+
+ #[test]
+ fn test_compare() {
+ let uuid1 = Uuid::new_v4();
+ let uuid2 = Uuid::new_v4();
+
+ assert!(uuid1 == uuid1);
+ assert!(uuid2 == uuid2);
+ assert!(uuid1 != uuid2);
+ assert!(uuid2 != uuid1);
+ }
+
+ #[test]
+ fn test_from_fields() {
+ let d1: u32 = 0xa1a2a3a4;
+ let d2: u16 = 0xb1b2;
+ let d3: u16 = 0xc1c2;
+ let d4: ~[u8] = ~[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8];
+
+ let u = Uuid::from_fields(d1, d2, d3, d4);
+
+ let expected = ~"a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
+ let result = u.to_simple_str();
+ assert!(result == expected);
+ }
+
+ #[test]
+ fn test_from_bytes() {
+ let b = ~[ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
+ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 ];
+
+ let u = Uuid::from_bytes(b).unwrap();
+ let expected = ~"a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
+
+ assert!(u.to_simple_str() == expected);
+ }
+
+ #[test]
+ fn test_to_bytes() {
+ let u = Uuid::new_v4();
+ let ub = u.to_bytes();
+
+ assert!(ub.len() == 16);
+ assert!(! ub.iter().all(|&b| b == 0));
+ }
+
+ #[test]
+ fn test_bytes_roundtrip() {
+ let b_in: [u8, ..16] = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
+ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 ];
+
+ let u = Uuid::from_bytes(b_in.clone()).unwrap();
+
+ let b_out = u.to_bytes();
+
+ assert!(b_in == b_out);
+ }
+
+ #[test]
+ fn test_operator_eq() {
+ let u1 = Uuid::new_v4();
+ let u2 = u1.clone();
+ let u3 = Uuid::new_v4();
+
+ assert!(u1 == u1);
+ assert!(u1 == u2);
+ assert!(u2 == u1);
+
+ assert!(u1 != u3);
+ assert!(u3 != u1);
+ assert!(u2 != u3);
+ assert!(u3 != u2);
+ }
+
+ #[test]
+ fn test_rand_rand() {
+ let mut rng = rand::rng();
+ let u: ~Uuid = rand::Rand::rand(&mut rng);
+ let ub = u.to_bytes();
+
+ assert!(ub.len() == 16);
+ assert!(! ub.iter().all(|&b| b == 0));
+ }
+}
+
+#[cfg(test)]
+mod bench {
+ use super::*;
+ use test::BenchHarness;
+
+ #[bench]
+ pub fn create_uuids(bh: &mut BenchHarness) {
+ do bh.iter {
+ Uuid::new_v4();
+ }
+ }
+
+ #[bench]
+ pub fn uuid_to_str(bh: &mut BenchHarness) {
+ let u = Uuid::new_v4();
+ do bh.iter {
+ u.to_str();
+ }
+ }
+
+ #[bench]
+ pub fn parse_str(bh: &mut BenchHarness) {
+ let s = "urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4";
+ do bh.iter {
+ let u = Uuid::parse_string(s);
+ }
+ }
+}
}
pub fn main() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let os_args = os::args();
if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
OptLevel: c_int,
EnableSegmentedStacks: bool) {
unsafe {
- do Triple.to_c_str().with_ref |Triple| {
- do Cpu.to_c_str().with_ref |Cpu| {
- do Feature.to_c_str().with_ref |Feature| {
- do Output.to_c_str().with_ref |Output| {
+ do Triple.with_c_str |Triple| {
+ do Cpu.with_c_str |Cpu| {
+ do Feature.with_c_str |Feature| {
+ do Output.with_c_str |Output| {
let result = llvm::LLVMRustWriteOutputFile(
PM,
M,
debug!("linking: %s", path);
- do path.to_c_str().with_ref |buf_t| {
+ do path.with_c_str |buf_t| {
if !llvm::LLVMRustLoadCrate(manager, buf_t) {
llvm_err(sess, ~"Could not link");
}
// Next, we need to get a handle on the _rust_main function by
// looking up it's corresponding ValueRef and then requesting that
// the execution engine compiles the function.
- let fun = do "_rust_main".to_c_str().with_ref |entry| {
+ let fun = do "_rust_main".with_c_str |entry| {
llvm::LLVMGetNamedFunction(m, entry)
};
if fun.is_null() {
output_type_bitcode => {
if opts.optimize != session::No {
let filename = output.with_filetype("no-opt.bc");
- do filename.to_c_str().with_ref |buf| {
+ do filename.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf);
}
}
}
_ => {
let filename = output.with_filetype("bc");
- do filename.to_c_str().with_ref |buf| {
+ do filename.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf);
}
}
// Always output the bitcode file with --save-temps
let filename = output.with_filetype("opt.bc");
- do filename.to_c_str().with_ref |buf| {
+ do filename.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf)
};
// Save the assembly file if -S is used
if output_type == output_type_llvm_assembly {
// Given options "-S --emit-llvm": output LLVM assembly
- do output.to_c_str().with_ref |buf_o| {
+ do output.with_c_str |buf_o| {
llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o);
}
} else {
// If only a bitcode file is asked for by using the
// '--emit-llvm' flag, then output it here
- do output.to_c_str().with_ref |buf| {
+ do output.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf);
}
}
}
pub fn create_pass(name:&str) -> Option<PassRef> {
- do name.to_c_str().with_ref |s| {
+ do name.with_c_str |s| {
unsafe {
let p = llvm::LLVMCreatePass(s);
if p.is_null() {
pub struct Upcalls {
trace: ValueRef,
- call_shim_on_c_stack: ValueRef,
- call_shim_on_rust_stack: ValueRef,
rust_personality: ValueRef,
reset_stack_limit: ValueRef
}
@Upcalls {
trace: upcall!(fn trace(opaque_ptr, opaque_ptr, int_ty) -> Type::void()),
- call_shim_on_c_stack: upcall!(fn call_shim_on_c_stack(opaque_ptr, opaque_ptr) -> int_ty),
- call_shim_on_rust_stack:
- upcall!(fn call_shim_on_rust_stack(opaque_ptr, opaque_ptr) -> int_ty),
rust_personality: upcall!(nothrow fn rust_personality -> Type::i32()),
reset_stack_limit: upcall!(nothrow fn reset_stack_limit -> Type::void())
}
}
}
-pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
+pub fn default_configuration(sess: Session) ->
ast::CrateConfig {
- let (libc, tos) = match sess.targ_cfg.os {
- session::os_win32 => (@"msvcrt.dll", @"win32"),
- session::os_macos => (@"libc.dylib", @"macos"),
- session::os_linux => (@"libc.so.6", @"linux"),
- session::os_android => (@"libc.so", @"android"),
- session::os_freebsd => (@"libc.so.7", @"freebsd")
+ let tos = match sess.targ_cfg.os {
+ session::os_win32 => @"win32",
+ session::os_macos => @"macos",
+ session::os_linux => @"linux",
+ session::os_android => @"android",
+ session::os_freebsd => @"freebsd"
};
// ARM is bi-endian, however using NDK seems to default
mk(@"target_arch", arch),
mk(@"target_endian", end),
mk(@"target_word_size", wordsz),
- mk(@"target_libc", libc),
- // Build bindings.
- mk(@"build_compiler", argv0),
- mk(@"build_input", source_name(input))];
+ ];
}
pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
}
}
-pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
+pub fn build_configuration(sess: Session) ->
ast::CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items
- let default_cfg = default_configuration(sess, argv0, input);
+ let default_cfg = default_configuration(sess);
let mut user_cfg = sess.opts.cfg.clone();
// If the user wants a test runner, then add the test cfg
if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
time(time_passes, ~"loop checking", ||
middle::check_loop::check_crate(ty_cx, crate));
+ time(time_passes, ~"stack checking", ||
+ middle::stack_check::stack_check_crate(ty_cx, crate));
+
let middle::moves::MoveMaps {moves_map, moved_variables_set,
capture_map} =
time(time_passes, ~"compute moves", ||
}
debugging_opts |= this_bit;
}
+
if debugging_opts & session::debug_llvm != 0 {
- unsafe {
- llvm::LLVMSetDebug(1);
+ set_llvm_debug();
+
+ fn set_llvm_debug() {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { llvm::LLVMSetDebug(1); }
}
}
let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
let debuginfo = debugging_opts & session::debug_info != 0 ||
extra_debuginfo;
+
+ // If debugging info is generated, do not collapse monomorphized function instances.
+ // Functions with equivalent llvm code still need separate debugging descriptions because names
+ // might differ.
+ if debuginfo {
+ debugging_opts |= session::no_monomorphic_collapse;
+ }
+
let statik = debugging_opts & session::statik != 0;
let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
mod test {
use driver::driver::{build_configuration, build_session};
- use driver::driver::{build_session_options, optgroups, str_input};
+ use driver::driver::{build_session_options, optgroups};
use extra::getopts::groups::getopts;
use extra::getopts;
let sessopts = build_session_options(
@"rustc", matches, diagnostic::emit);
let sess = build_session(sessopts, diagnostic::emit);
- let cfg = build_configuration(sess, @"whatever", &str_input(@""));
+ let cfg = build_configuration(sess);
assert!((attr::contains_name(cfg, "test")));
}
let sessopts = build_session_options(
@"rustc", matches, diagnostic::emit);
let sess = build_session(sessopts, diagnostic::emit);
- let cfg = build_configuration(sess, @"whatever", &str_input(@""));
+ let cfg = build_configuration(sess);
let mut test_items = cfg.iter().filter(|m| "test" == m.name());
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
}
}
+#[cfg(stage0)]
fn mk_test_module(cx: &TestCtxt) -> @ast::item {
// Link to extra
return @item;
}
+#[cfg(not(stage0))]
+fn mk_test_module(cx: &TestCtxt) -> @ast::item {
+
+ // Link to extra
+ let view_items = ~[mk_std(cx)];
+
+ // A constant vector of test descriptors.
+ let tests = mk_tests(cx);
+
+ // The synthesized main function which will call the console test runner
+ // with our list of tests
+ let mainfn = (quote_item!(cx.ext_cx,
+ pub fn main() {
+ #[main];
+ extra::test::test_main_static(::std::os::args(), TESTS);
+ }
+ )).unwrap();
+
+ let testmod = ast::_mod {
+ view_items: view_items,
+ items: ~[mainfn, tests],
+ };
+ let item_ = ast::item_mod(testmod);
+
+ // This attribute tells resolve to let us call unexported functions
+ let resolve_unexported_attr =
+ attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));
+
+ let item = ast::item {
+ ident: cx.sess.ident_of("__test"),
+ attrs: ~[resolve_unexported_attr],
+ id: cx.sess.next_node_id(),
+ node: item_,
+ vis: ast::public,
+ span: dummy_sp(),
+ };
+
+ debug!("Synthetic test module:\n%s\n",
+ pprust::item_to_str(@item.clone(), cx.sess.intr()));
+
+ return @item;
+}
fn nospan<T>(t: T) -> codemap::spanned<T> {
codemap::spanned { node: t, span: dummy_sp() }
types: ~[] }
}
+#[cfg(stage0)]
fn mk_tests(cx: &TestCtxt) -> @ast::item {
let ext_cx = cx.ext_cx;
;
)).unwrap()
}
+#[cfg(not(stage0))]
+fn mk_tests(cx: &TestCtxt) -> @ast::item {
+ // The vector of test_descs for this crate
+ let test_descs = mk_test_descs(cx);
+
+ (quote_item!(cx.ext_cx,
+ pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
+ $test_descs
+ ;
+ )).unwrap()
+}
fn is_extra(cx: &TestCtxt) -> bool {
let items = attr::find_linkage_metas(cx.crate.attrs);
}
}
+#[cfg(stage0)]
fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr {
let span = test.span;
let path = test.path.clone();
);
e
}
+#[cfg(not(stage0))]
+fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr {
+ let span = test.span;
+ let path = test.path.clone();
+
+ debug!("encoding %s", ast_util::path_name_i(path));
+
+ let name_lit: ast::lit =
+ nospan(ast::lit_str(ast_util::path_name_i(path).to_managed()));
+
+ let name_expr = @ast::expr {
+ id: cx.sess.next_node_id(),
+ node: ast::expr_lit(@name_lit),
+ span: span
+ };
+
+ let fn_path = path_node_global(path);
+
+ let fn_expr = @ast::expr {
+ id: cx.sess.next_node_id(),
+ node: ast::expr_path(fn_path),
+ span: span,
+ };
+
+ let t_expr = if test.bench {
+ quote_expr!(cx.ext_cx, self::extra::test::StaticBenchFn($fn_expr) )
+ } else {
+ quote_expr!(cx.ext_cx, self::extra::test::StaticTestFn($fn_expr) )
+ };
+
+ let ignore_expr = if test.ignore {
+ quote_expr!(cx.ext_cx, true )
+ } else {
+ quote_expr!(cx.ext_cx, false )
+ };
+
+ let fail_expr = if test.should_fail {
+ quote_expr!(cx.ext_cx, true )
+ } else {
+ quote_expr!(cx.ext_cx, false )
+ };
+
+ let e = quote_expr!(cx.ext_cx,
+ self::extra::test::TestDescAndFn {
+ desc: self::extra::test::TestDesc {
+ name: self::extra::test::StaticTestName($name_expr),
+ ignore: $ignore_expr,
+ should_fail: $fail_expr
+ },
+ testfn: $t_expr,
+ }
+ );
+ e
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// LLVM wrappers are intended to be called from trans,
+// which already runs in a #[fixed_stack_segment]
+#[allow(cstack)];
+
use std::c_str::ToCStr;
use std::hashmap::HashMap;
use std::libc::{c_uint, c_ushort};
#[fast_ffi]
pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool);
+
+ #[fast_ffi]
+ pub fn LLVMDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef,
+ Scope: ValueRef,
+ Name: *c_char,
+ Ty: ValueRef,
+ File: ValueRef,
+ LineNo: c_uint,
+ ColumnNo: c_uint)
+ -> ValueRef;
}
}
self.type_to_str_depth(ty, 30)
}
+ pub fn types_to_str(&self, tys: &[Type]) -> ~str {
+ let strs = tys.map(|t| self.type_to_str(*t));
+ fmt!("[%s]", strs.connect(","))
+ }
+
pub fn val_to_str(&self, val: ValueRef) -> ~str {
unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(val));
}
pub fn mk_target_data(string_rep: &str) -> TargetData {
- let lltd = do string_rep.to_c_str().with_ref |buf| {
+ let lltd = do string_rep.with_c_str |buf| {
unsafe { llvm::LLVMCreateTargetData(buf) }
};
warn_if_multiple_versions(e, diag, *e.crate_cache);
}
+#[deriving(Clone)]
struct cache_entry {
cnum: int,
span: span,
fn warn_if_multiple_versions(e: @mut Env,
diag: @mut span_handler,
crate_cache: &[cache_entry]) {
- use std::either::*;
-
if crate_cache.len() != 0u {
let name = loader::crate_name_from_metas(
*crate_cache[crate_cache.len() - 1].metas
);
- let vec: ~[Either<cache_entry, cache_entry>] = crate_cache.iter().map(|&entry| {
- let othername = loader::crate_name_from_metas(*entry.metas);
- if name == othername {
- Left(entry)
- } else {
- Right(entry)
- }
- }).collect();
- let (matches, non_matches) = partition(vec);
+ let (matches, non_matches) = crate_cache.partitioned(|entry|
+ name == loader::crate_name_from_metas(*entry.metas));
assert!(!matches.is_empty());
fn get_metadata_section(os: os,
filename: &Path) -> Option<@~[u8]> {
unsafe {
- let mb = do filename.to_c_str().with_ref |buf| {
+ let mb = do filename.with_c_str |buf| {
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
};
if mb as int == 0 { return option::None::<@~[u8]>; }
#[test]
fn test_basic() {
- let ext_cx = mk_ctxt();
- roundtrip(quote_item!(
+ let cx = mk_ctxt();
+ roundtrip(quote_item!(cx,
fn foo() {}
));
}
#[test]
fn test_smalltalk() {
- let ext_cx = mk_ctxt();
- roundtrip(quote_item!(
+ let cx = mk_ctxt();
+ roundtrip(quote_item!(cx,
fn foo() -> int { 3 + 4 } // first smalltalk program ever executed.
));
}
#[test]
fn test_more() {
- let ext_cx = mk_ctxt();
- roundtrip(quote_item!(
+ let cx = mk_ctxt();
+ roundtrip(quote_item!(cx,
fn foo(x: uint, y: uint) -> uint {
let z = x + y;
return z;
#[test]
fn test_simplification() {
- let ext_cx = mk_ctxt();
- let item_in = ast::ii_item(quote_item!(
+ let cx = mk_ctxt();
+ let item_in = ast::ii_item(quote_item!(cx,
fn new_int_alist<B>() -> alist<int, B> {
fn eq_int(a: int, b: int) -> bool { a == b }
return alist {eq_fn: eq_int, data: ~[]};
}
).unwrap());
let item_out = simplify_ast(&item_in);
- let item_exp = ast::ii_item(quote_item!(
+ let item_exp = ast::ii_item(quote_item!(cx,
fn new_int_alist<B>() -> alist<int, B> {
return alist {eq_fn: eq_int, data: ~[]};
}
expr_field(*) |
expr_index(*) |
expr_tup(*) |
+ expr_repeat(*) |
expr_struct(*) => { }
expr_addr_of(*) => {
sess.span_err(
let check_move: &fn(@pat, Option<@pat>) = |p, sub| {
// check legality of moving out of the enum
- if sub.is_some() {
+
+ // x @ Foo(*) is legal, but x @ Foo(y) isn't.
+ if sub.map_move_default(false, |p| pat_contains_bindings(def_map, p)) {
tcx.sess.span_err(
p.span,
"cannot bind by-move with sub-bindings");
lookup_constness(tcx, e)
}
+ ast::expr_repeat(*) => general_const,
+
_ => non_const
};
tcx.ccache.insert(did, cn);
StrEqFnLangItem, // 19
UniqStrEqFnLangItem, // 20
- AnnihilateFnLangItem, // 21
- LogTypeFnLangItem, // 22
- FailFnLangItem, // 23
- FailBoundsCheckFnLangItem, // 24
- ExchangeMallocFnLangItem, // 25
- ClosureExchangeMallocFnLangItem, // 26
- ExchangeFreeFnLangItem, // 27
- MallocFnLangItem, // 28
- FreeFnLangItem, // 29
- BorrowAsImmFnLangItem, // 30
- BorrowAsMutFnLangItem, // 31
- ReturnToMutFnLangItem, // 32
- CheckNotBorrowedFnLangItem, // 33
- StrDupUniqFnLangItem, // 34
- RecordBorrowFnLangItem, // 35
- UnrecordBorrowFnLangItem, // 36
-
- StartFnLangItem, // 37
-
- TyDescStructLangItem, // 38
- TyVisitorTraitLangItem, // 39
- OpaqueStructLangItem, // 40
+ LogTypeFnLangItem, // 21
+ FailFnLangItem, // 22
+ FailBoundsCheckFnLangItem, // 23
+ ExchangeMallocFnLangItem, // 24
+ ClosureExchangeMallocFnLangItem, // 25
+ ExchangeFreeFnLangItem, // 26
+ MallocFnLangItem, // 27
+ FreeFnLangItem, // 28
+ BorrowAsImmFnLangItem, // 29
+ BorrowAsMutFnLangItem, // 30
+ ReturnToMutFnLangItem, // 31
+ CheckNotBorrowedFnLangItem, // 32
+ StrDupUniqFnLangItem, // 33
+ RecordBorrowFnLangItem, // 34
+ UnrecordBorrowFnLangItem, // 35
+
+ StartFnLangItem, // 36
+
+ TyDescStructLangItem, // 37
+ TyVisitorTraitLangItem, // 38
+ OpaqueStructLangItem, // 39
}
pub struct LanguageItems {
19 => "str_eq",
20 => "uniq_str_eq",
- 21 => "annihilate",
- 22 => "log_type",
- 23 => "fail_",
- 24 => "fail_bounds_check",
- 25 => "exchange_malloc",
- 26 => "closure_exchange_malloc",
- 27 => "exchange_free",
- 28 => "malloc",
- 29 => "free",
- 30 => "borrow_as_imm",
- 31 => "borrow_as_mut",
- 32 => "return_to_mut",
- 33 => "check_not_borrowed",
- 34 => "strdup_uniq",
- 35 => "record_borrow",
- 36 => "unrecord_borrow",
-
- 37 => "start",
-
- 38 => "ty_desc",
- 39 => "ty_visitor",
- 40 => "opaque",
+ 21 => "log_type",
+ 22 => "fail_",
+ 23 => "fail_bounds_check",
+ 24 => "exchange_malloc",
+ 25 => "closure_exchange_malloc",
+ 26 => "exchange_free",
+ 27 => "malloc",
+ 28 => "free",
+ 29 => "borrow_as_imm",
+ 30 => "borrow_as_mut",
+ 31 => "return_to_mut",
+ 32 => "check_not_borrowed",
+ 33 => "strdup_uniq",
+ 34 => "record_borrow",
+ 35 => "unrecord_borrow",
+
+ 36 => "start",
+
+ 37 => "ty_desc",
+ 38 => "ty_visitor",
+ 39 => "opaque",
_ => "???"
}
pub fn uniq_str_eq_fn(&self) -> Option<def_id> {
self.items[UniqStrEqFnLangItem as uint]
}
- pub fn annihilate_fn(&self) -> Option<def_id> {
- self.items[AnnihilateFnLangItem as uint]
- }
pub fn log_type_fn(&self) -> Option<def_id> {
self.items[LogTypeFnLangItem as uint]
}
item_refs.insert(@"str_eq", StrEqFnLangItem as uint);
item_refs.insert(@"uniq_str_eq", UniqStrEqFnLangItem as uint);
- item_refs.insert(@"annihilate", AnnihilateFnLangItem as uint);
item_refs.insert(@"log_type", LogTypeFnLangItem as uint);
item_refs.insert(@"fail_", FailFnLangItem as uint);
item_refs.insert(@"fail_bounds_check",
#[deriving(Clone, Eq)]
pub enum lint {
ctypes,
+ cstack,
unused_imports,
unnecessary_qualification,
while_true,
default: warn
}),
+ ("cstack",
+ LintSpec {
+ lint: cstack,
+ desc: "only invoke foreign functions from fixedstacksegment fns",
+ default: deny
+ }),
+
("unused_imports",
LintSpec {
lint: unused_imports,
(orig.visit_item)(it, (self, stopping));
}
NewVisitor(new_visitor) => {
- let mut new_visitor = new_visitor;
+ let new_visitor = new_visitor;
new_visitor.visit_item(it, ());
}
}
let fk = visit::fk_method(m.ident,
&m.generics,
m);
- let mut new_visitor = new_visitor;
+ let new_visitor = new_visitor;
new_visitor.visit_fn(&fk,
&m.decl,
&m.body,
pat_bindings(dm, pat, |_bm, b_id, _sp, _pt| found.push(b_id) );
return found;
}
+
+/// Checks if the pattern contains any patterns that bind something to
+/// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(*)`.
+pub fn pat_contains_bindings(dm: resolve::DefMap, pat: @pat) -> bool {
+ let mut contains_bindings = false;
+ do walk_pat(pat) |p| {
+ if pat_is_binding(dm, p) {
+ contains_bindings = true;
+ false // there's at least one binding, can short circuit now.
+ } else {
+ true
+ }
+ };
+ contains_bindings
+}
--- /dev/null
+// Copyright 2012-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.
+
+/*!
+
+Lint mode to detect cases where we call non-Rust fns, which do not
+have a stack growth check, from locations not annotated to request
+large stacks.
+
+*/
+
+use middle::lint;
+use middle::ty;
+use syntax::ast;
+use syntax::ast_map;
+use syntax::attr;
+use syntax::codemap::span;
+use visit = syntax::oldvisit;
+use util::ppaux::Repr;
+
+#[deriving(Clone)]
+struct Context {
+ tcx: ty::ctxt,
+ safe_stack: bool
+}
+
+pub fn stack_check_crate(tcx: ty::ctxt,
+ crate: &ast::Crate) {
+ let new_cx = Context {
+ tcx: tcx,
+ safe_stack: false
+ };
+ let visitor = visit::mk_vt(@visit::Visitor {
+ visit_item: stack_check_item,
+ visit_fn: stack_check_fn,
+ visit_expr: stack_check_expr,
+ ..*visit::default_visitor()
+ });
+ visit::visit_crate(crate, (new_cx, visitor));
+}
+
+fn stack_check_item(item: @ast::item,
+ (in_cx, v): (Context, visit::vt<Context>)) {
+ match item.node {
+ ast::item_fn(_, ast::extern_fn, _, _, _) => {
+ // an extern fn is already being called from C code...
+ let new_cx = Context {safe_stack: true, ..in_cx};
+ visit::visit_item(item, (new_cx, v));
+ }
+ ast::item_fn(*) => {
+ let safe_stack = fixed_stack_segment(item.attrs);
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ visit::visit_item(item, (new_cx, v));
+ }
+ ast::item_impl(_, _, _, ref methods) => {
+ // visit_method() would make this nicer
+ for &method in methods.iter() {
+ let safe_stack = fixed_stack_segment(method.attrs);
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ visit::visit_method_helper(method, (new_cx, v));
+ }
+ }
+ _ => {
+ visit::visit_item(item, (in_cx, v));
+ }
+ }
+
+ fn fixed_stack_segment(attrs: &[ast::Attribute]) -> bool {
+ attr::contains_name(attrs, "fixed_stack_segment")
+ }
+}
+
+fn stack_check_fn<'a>(fk: &visit::fn_kind,
+ decl: &ast::fn_decl,
+ body: &ast::Block,
+ sp: span,
+ id: ast::NodeId,
+ (in_cx, v): (Context, visit::vt<Context>)) {
+ let safe_stack = match *fk {
+ visit::fk_method(*) | visit::fk_item_fn(*) => {
+ in_cx.safe_stack // see stack_check_item above
+ }
+ visit::fk_anon(*) | visit::fk_fn_block => {
+ match ty::get(ty::node_id_to_type(in_cx.tcx, id)).sty {
+ ty::ty_bare_fn(*) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
+ false
+ }
+ _ => {
+ in_cx.safe_stack
+ }
+ }
+ }
+ };
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
+ visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
+}
+
+fn stack_check_expr<'a>(expr: @ast::expr,
+ (cx, v): (Context, visit::vt<Context>)) {
+ debug!("stack_check_expr(safe_stack=%b, expr=%s)",
+ cx.safe_stack, expr.repr(cx.tcx));
+ if !cx.safe_stack {
+ match expr.node {
+ ast::expr_call(callee, _, _) => {
+ let callee_ty = ty::expr_ty(cx.tcx, callee);
+ debug!("callee_ty=%s", callee_ty.repr(cx.tcx));
+ match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref fty) => {
+ if !fty.abis.is_rust() && !fty.abis.is_intrinsic() {
+ call_to_extern_fn(cx, callee);
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+ visit::visit_expr(expr, (cx, v));
+}
+
+fn call_to_extern_fn(cx: Context, callee: @ast::expr) {
+ // Permit direct calls to extern fns that are annotated with
+ // #[rust_stack]. This is naturally a horrible pain to achieve.
+ match callee.node {
+ ast::expr_path(*) => {
+ match cx.tcx.def_map.find(&callee.id) {
+ Some(&ast::def_fn(id, _)) if id.crate == ast::LOCAL_CRATE => {
+ match cx.tcx.items.find(&id.node) {
+ Some(&ast_map::node_foreign_item(item, _, _, _)) => {
+ if attr::contains_name(item.attrs, "rust_stack") {
+ return;
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+
+ cx.tcx.sess.add_lint(lint::cstack,
+ callee.id,
+ callee.span,
+ fmt!("invoking non-Rust fn in fn without \
+ #[fixed_stack_segment]"));
+}
bindings_map: @BindingsMap
}
+/**
+ * Info about Match.
+ * If all `pats` are matched then arm `data` will be executed.
+ * As we proceed `bound_ptrs` are filled with pointers to values to be bound,
+ * these pointers are stored in llmatch variables just before executing `data` arm.
+ */
#[deriving(Clone)]
struct Match<'self> {
pats: ~[@ast::pat],
- data: ArmData<'self>
+ data: ArmData<'self>,
+ bound_ptrs: ~[(ident, ValueRef)]
}
impl<'self> Repr for Match<'self> {
br.pats.slice(col + 1u,
br.pats.len())));
- let binding_info =
- br.data.bindings_map.get(&path_to_ident(path));
-
- Store(bcx, val, binding_info.llmatch);
- Match {
+ let mut res = Match {
pats: pats,
- data: br.data.clone()
- }
+ data: br.data.clone(),
+ bound_ptrs: br.bound_ptrs.clone()
+ };
+ res.bound_ptrs.push((path_to_ident(path), val));
+ res
}
_ => (*br).clone(),
}
br.pats.slice(col + 1u, br.pats.len()));
let this = br.pats[col];
+ let mut bound_ptrs = br.bound_ptrs.clone();
match this.node {
ast::pat_ident(_, ref path, None) => {
if pat_is_binding(dm, this) {
- let binding_info =
- br.data.bindings_map.get(
- &path_to_ident(path));
- Store(bcx, val, binding_info.llmatch);
+ bound_ptrs.push((path_to_ident(path), val));
}
}
_ => {}
result.push(Match {
pats: pats,
- data: br.data.clone()
+ data: br.data.clone(),
+ bound_ptrs: bound_ptrs
});
}
None => ()
fn insert_lllocals(bcx: @mut Block,
bindings_map: &BindingsMap,
- binding_mode: IrrefutablePatternBindingMode,
add_cleans: bool) -> @mut Block {
/*!
* For each binding in `data.bindings_map`, adds an appropriate entry into
* the bindings.
*/
- let llmap = match binding_mode {
- BindLocal => bcx.fcx.lllocals,
- BindArgument => bcx.fcx.llargs
- };
+ let llmap = bcx.fcx.lllocals;
for (&ident, &binding_info) in bindings_map.iter() {
let llval = match binding_info.trmode {
bcx = store_non_ref_bindings(bcx,
data.bindings_map,
Some(&mut temp_cleanups));
- bcx = insert_lllocals(bcx, data.bindings_map, BindLocal, false);
+ bcx = insert_lllocals(bcx, data.bindings_map, false);
let val = unpack_result!(bcx, {
do with_scope_result(bcx, guard_expr.info(),
}
if m[0].pats.len() == 0u {
let data = &m[0].data;
+ for &(ref ident, ref value_ptr) in m[0].bound_ptrs.iter() {
+ let llmatch = data.bindings_map.get(ident).llmatch;
+ Store(bcx, *value_ptr, llmatch);
+ }
match data.arm.guard {
Some(guard_expr) => {
bcx = compile_guard(bcx,
matches.push(Match {
pats: ~[*p],
data: arm_data.clone(),
+ bound_ptrs: ~[],
});
}
}
}
// insert bindings into the lllocals map and add cleanups
- bcx = insert_lllocals(bcx, arm_data.bindings_map, BindLocal, true);
+ bcx = insert_lllocals(bcx, arm_data.bindings_map, true);
bcx = controlflow::trans_block(bcx, &arm_data.arm.body, dest);
bcx = trans_block_cleanups(bcx, block_cleanups(arm_data.bodycx));
ast::asm_intel => lib::llvm::AD_Intel
};
- let r = do ia.asm.to_c_str().with_ref |a| {
- do constraints.to_c_str().with_ref |c| {
+ let r = do ia.asm.with_c_str |a| {
+ do constraints.with_c_str |c| {
InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
}
};
fn fcx_has_nonzero_span(fcx: &FunctionContext) -> bool {
match fcx.span {
- None => true,
+ None => false,
Some(span) => *span.lo != 0 || *span.hi != 0
}
}
}
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
- let llfn: ValueRef = do name.to_c_str().with_ref |buf| {
+ let llfn: ValueRef = do name.with_c_str |buf| {
unsafe {
llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref())
}
return llfn;
}
-pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: @str,
+pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
- match externs.find_copy(&name) {
- Some(n) => return n,
+ match externs.find_equiv(&name) {
+ Some(n) => return *n,
None => ()
}
let f = decl_fn(llmod, name, cc, ty);
- externs.insert(name, f);
+ externs.insert(name.to_owned(), f);
return f;
}
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
- name: @str, ty: Type) -> ValueRef {
- match externs.find_copy(&name) {
- Some(n) => return n,
+ name: &str, ty: Type) -> ValueRef {
+ match externs.find_equiv(&name) {
+ Some(n) => return *n,
None => ()
}
unsafe {
- let c = do name.to_c_str().with_ref |buf| {
+ let c = do name.with_c_str |buf| {
llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf)
};
- externs.insert(name, c);
+ externs.insert(name.to_owned(), c);
return c;
}
}
None,
ty::lookup_item_type(tcx, parent_id).ty);
let llty = type_of_dtor(ccx, class_ty);
- let name = name.to_managed(); // :-(
get_extern_fn(&mut ccx.externs,
ccx.llmod,
name,
// Structural comparison: a rather involved form of glue.
pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
if cx.sess.opts.save_temps {
- do s.to_c_str().with_ref |buf| {
+ do s.with_c_str |buf| {
unsafe {
llvm::LLVMSetValueName(v, buf)
}
}
}
-pub fn null_env_ptr(bcx: @mut Block) -> ValueRef {
- C_null(Type::opaque_box(bcx.ccx()).ptr_to())
+pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
+ C_null(Type::opaque_box(ccx).ptr_to())
}
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::def_id, t: ty::t)
-> ValueRef {
- let name = csearch::get_symbol(ccx.sess.cstore, did).to_managed(); // Sad
+ let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty {
ty::ty_bare_fn(_) | ty::ty_closure(_) => {
let llty = type_of_fn_from_ty(ccx, t);
opt_node_info: Option<NodeInfo>)
-> @mut Block {
unsafe {
- let llbb = do name.to_c_str().with_ref |buf| {
+ let llbb = do name.with_c_str |buf| {
llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf)
};
let bcx = @mut Block::new(llbb,
pub fn mk_staticallocas_basic_block(llfn: ValueRef) -> BasicBlockRef {
unsafe {
let cx = task_llcx();
- do "static_allocas".to_c_str().with_ref | buf| {
+ do "static_allocas".with_c_str | buf| {
llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)
}
}
pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef {
unsafe {
let cx = task_llcx();
- do "return".to_c_str().with_ref |buf| {
+ do "return".with_c_str |buf| {
llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)
}
}
// slot where the return value of the function must go.
pub fn make_return_pointer(fcx: @mut FunctionContext, output_type: ty::t) -> ValueRef {
unsafe {
- if !ty::type_is_immediate(fcx.ccx.tcx, output_type) {
+ if type_of::return_uses_outptr(fcx.ccx.tcx, output_type) {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
}
};
- let is_immediate = ty::type_is_immediate(ccx.tcx, substd_output_type);
+ let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type);
let fcx = @mut FunctionContext {
llfn: llfndecl,
llenv: unsafe {
llreturn: None,
llself: None,
personality: None,
- has_immediate_return_value: is_immediate,
+ caller_expects_out_pointer: uses_outptr,
llargs: @mut HashMap::new(),
lllocals: @mut HashMap::new(),
llupvars: @mut HashMap::new(),
fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
}
- if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
- fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
+ if !ty::type_is_voidish(substd_output_type) {
+ // If the function returns nil/bot, there is no real return
+ // value, so do not set `llretptr`.
+ if !skip_retptr || uses_outptr {
+ // Otherwise, we normally allocate the llretptr, unless we
+ // have been instructed to skip it for immediate return
+ // values.
+ fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
+ }
}
fcx
}
fcx.llself = Some(ValSelfData {v: self_val, ..slf});
add_clean(bcx, self_val, slf.t);
+
+ if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
+ debuginfo::create_self_argument_metadata(bcx, slf.t, self_val);
+ }
}
_ => {}
}
// Builds the return block for a function.
pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
// Return the value if this function immediate; otherwise, return void.
- if fcx.llretptr.is_none() || !fcx.has_immediate_return_value {
+ if fcx.llretptr.is_none() || fcx.caller_expects_out_pointer {
return RetVoid(ret_cx);
}
set_fixed_stack_segment(fcx.llfn);
}
+ if ccx.sess.opts.debuginfo && fcx_has_nonzero_span(fcx) {
+ debuginfo::create_function_metadata(fcx);
+ }
+
// Create the first basic block in the function and keep a handle on it to
// pass to finish_fn later.
let bcx_top = fcx.entry_bcx.unwrap();
// translation calls that don't have a return value (trans_crate,
// trans_mod, trans_item, et cetera) and those that do
// (trans_block, trans_expr, et cetera).
- if body.expr.is_none() || ty::type_is_bot(block_ty) ||
- ty::type_is_nil(block_ty)
- {
+ if body.expr.is_none() || ty::type_is_voidish(block_ty) {
bcx = controlflow::trans_block(bcx, body, expr::Ignore);
} else {
let dest = expr::SaveIn(fcx.llretptr.unwrap());
id,
attrs,
output_type,
- |fcx| {
- if ccx.sess.opts.debuginfo
- && fcx_has_nonzero_span(fcx) {
- debuginfo::create_function_metadata(fcx);
- }
- });
+ |_fcx| { });
}
fn insert_synthetic_type_entries(bcx: @mut Block,
ast::item_fn(ref decl, purity, _abis, ref generics, ref body) => {
if purity == ast::extern_fn {
let llfndecl = get_item_val(ccx, item.id);
- foreign::trans_foreign_fn(ccx,
- vec::append((*path).clone(),
- [path_name(item.ident)]),
- decl,
- body,
- llfndecl,
- item.id);
+ foreign::trans_rust_fn_with_foreign_abi(
+ ccx,
+ &vec::append((*path).clone(),
+ [path_name(item.ident)]),
+ decl,
+ body,
+ llfndecl,
+ item.id);
} else if !generics.is_type_parameterized() {
let llfndecl = get_item_val(ccx, item.id);
trans_fn(ccx,
}
},
ast::item_foreign_mod(ref foreign_mod) => {
- foreign::trans_foreign_mod(ccx, path, foreign_mod);
+ foreign::trans_foreign_mod(ccx, foreign_mod);
}
ast::item_struct(struct_def, ref generics) => {
if !generics.is_type_parameterized() {
fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
let nt = ty::mk_nil();
-
- let llfty = type_of_fn(ccx, [], nt);
+ let llfty = type_of_rust_fn(ccx, [], nt);
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
lib::llvm::CCallConv, llfty);
// the args vector built in create_entry_fn will need
// be updated if this assertion starts to fail.
- assert!(fcx.has_immediate_return_value);
+ assert!(!fcx.caller_expects_out_pointer);
let bcx = fcx.entry_bcx.unwrap();
// Call main.
};
decl_cdecl_fn(ccx.llmod, main_name, llfty)
};
- let llbb = do "top".to_c_str().with_ref |buf| {
+ let llbb = do "top".with_c_str |buf| {
unsafe {
llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
}
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
let crate_map = ccx.crate_map;
- let opaque_crate_map = do "crate_map".to_c_str().with_ref |buf| {
+ let opaque_crate_map = do "crate_map".with_c_str |buf| {
llvm::LLVMBuildPointerCast(bld, crate_map, Type::i8p().to_ref(), buf)
};
};
let args = {
- let opaque_rust_main = do "rust_main".to_c_str().with_ref |buf| {
+ let opaque_rust_main = do "rust_main".with_c_str |buf| {
llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p().to_ref(), buf)
};
unsafe {
let llty = llvm::LLVMTypeOf(v);
- let g = do sym.to_c_str().with_ref |buf| {
+ let g = do sym.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
};
let llfn = if purity != ast::extern_fn {
register_fn(ccx, i.span, sym, i.id, ty)
} else {
- foreign::register_foreign_fn(ccx, i.span, sym, i.id)
+ foreign::register_rust_fn_with_foreign_abi(ccx,
+ i.span,
+ sym,
+ i.id)
};
set_inline_hint_if_appr(i.attrs, llfn);
llfn
match (attr::first_attr_value_str_by_name(i.attrs, "link_section")) {
Some(sect) => unsafe {
- do sect.to_c_str().with_ref |buf| {
+ do sect.with_c_str |buf| {
llvm::LLVMSetSection(v, buf);
}
},
register_method(ccx, id, pth, m)
}
- ast_map::node_foreign_item(ni, _, _, pth) => {
+ ast_map::node_foreign_item(ni, abis, _, pth) => {
let ty = ty::node_id_to_type(ccx.tcx, ni.id);
exprt = true;
match ni.node {
ast::foreign_item_fn(*) => {
let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
- let sym = exported_name(ccx, path, ty, ni.attrs);
-
- register_fn(ccx, ni.span, sym, ni.id, ty)
+ foreign::register_foreign_item_fn(ccx, abis, &path, ni)
}
ast::foreign_item_static(*) => {
let ident = token::ident_to_str(&ni.ident);
- let g = do ident.to_c_str().with_ref |buf| {
+ let g = do ident.with_c_str |buf| {
unsafe {
let ty = type_of(ccx, ty);
llvm::LLVMAddGlobal(ccx.llmod, ty.to_ref(), buf)
let s = mangle_exported_name(ccx, p, ty::mk_int()).to_managed();
let disr_val = vi[i].disr_val;
note_unique_llvm_symbol(ccx, s);
- let discrim_gvar = do s.to_c_str().with_ref |buf| {
+ let discrim_gvar = do s.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)
}
}
let gc_metadata_name = ~"_gc_module_metadata_" + llmod_id;
- let gc_metadata = do gc_metadata_name.to_c_str().with_ref |buf| {
+ let gc_metadata = do gc_metadata_name.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
}
pub fn create_module_map(ccx: &mut CrateContext) -> ValueRef {
let elttype = Type::struct_([ccx.int_type, ccx.int_type], false);
let maptype = Type::array(&elttype, (ccx.module_data.len() + 1) as u64);
- let map = do "_rust_mod_map".to_c_str().with_ref |buf| {
+ let map = do "_rust_mod_map".with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, maptype.to_ref(), buf)
}
let sym_name = ~"_rust_crate_map_" + mapname;
let arrtype = Type::array(&int_type, n_subcrates as u64);
let maptype = Type::struct_([Type::i32(), Type::i8p(), int_type, arrtype], false);
- let map = do sym_name.to_c_str().with_ref |buf| {
+ let map = do sym_name.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(llmod, maptype.to_ref(), buf)
}
cdata.name,
cstore::get_crate_vers(cstore, i),
cstore::get_crate_hash(cstore, i));
- let cr = do nm.to_c_str().with_ref |buf| {
+ let cr = do nm.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)
}
}
subcrates.push(C_int(ccx, 0));
- let llannihilatefn = match ccx.tcx.lang_items.annihilate_fn() {
- Some(annihilate_def_id) => {
- if annihilate_def_id.crate == ast::LOCAL_CRATE {
- get_item_val(ccx, annihilate_def_id.node)
- } else {
- let annihilate_fn_type = csearch::get_type(ccx.tcx,
- annihilate_def_id).ty;
- trans_external_path(ccx, annihilate_def_id, annihilate_fn_type)
- }
- }
- None => { C_null(Type::i8p()) }
- };
-
unsafe {
let mod_map = create_module_map(ccx);
llvm::LLVMSetInitializer(map, C_struct(
[C_i32(1),
- lib::llvm::llvm::LLVMConstPointerCast(llannihilatefn, Type::i8p().to_ref()),
+ // FIXME #8431 This used to be the annihilate function, now it's nothing
+ C_null(Type::i8p()),
p2i(ccx, mod_map),
C_array(ccx.int_type, subcrates)]));
}
let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item);
let llmeta = C_bytes(encoder::encode_metadata(encode_parms, crate));
let llconst = C_struct([llmeta]);
- let mut llglobal = do "rust_metadata".to_c_str().with_ref |buf| {
+ let mut llglobal = do "rust_metadata".with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst).to_ref(), buf)
}
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
- do cx.sess.targ_cfg.target_strs.meta_sect_name.to_c_str().with_ref |buf| {
+ do cx.sess.targ_cfg.target_strs.meta_sect_name.with_c_str |buf| {
llvm::LLVMSetSection(llglobal, buf)
};
lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
let t_ptr_i8 = Type::i8p();
llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8.to_ref());
- let llvm_used = do "llvm.used".to_c_str().with_ref |buf| {
+ let llvm_used = do "llvm.used".with_c_str |buf| {
llvm::LLVMAddGlobal(cx.llmod, Type::array(&t_ptr_i8, 1).to_ref(), buf)
};
lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage);
internal: bool)
-> ValueRef {
unsafe {
- let llglobal = do name.to_c_str().with_ref |buf| {
+ let llglobal = do name.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval).to_ref(), buf)
};
llvm::LLVMSetInitializer(llglobal, llval);
if name.is_empty() {
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
} else {
- do name.to_c_str().with_ref |c| {
+ do name.with_c_str |c| {
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c)
}
}
let sanitized = text.replace("$", "");
let comment_text = fmt!("# %s", sanitized.replace("\n", "\n\t# "));
self.count_insn("inlineasm");
- let asm = do comment_text.to_c_str().with_ref |c| {
+ let asm = do comment_text.with_c_str |c| {
unsafe {
llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(),
c, noname(), False, False)
let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
- let T: ValueRef = do "llvm.trap".to_c_str().with_ref |buf| {
+ let T: ValueRef = do "llvm.trap".with_c_str |buf| {
llvm::LLVMGetNamedFunction(M, buf)
};
assert!((T as int != 0));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use lib::llvm::{llvm, ValueRef, Attribute, Void};
-use middle::trans::base::*;
-use middle::trans::build::*;
-use middle::trans::common::*;
-
-use middle::trans::type_::Type;
-
-use std::libc::c_uint;
+use lib::llvm::Attribute;
use std::option;
-
-pub trait ABIInfo {
- fn compute_info(&self, atys: &[Type], rty: Type, ret_def: bool) -> FnType;
-}
+use middle::trans::context::CrateContext;
+use middle::trans::cabi_x86;
+use middle::trans::cabi_x86_64;
+use middle::trans::cabi_arm;
+use middle::trans::cabi_mips;
+use middle::trans::type_::Type;
+use syntax::abi::{X86, X86_64, Arm, Mips};
#[deriving(Clone)]
pub struct LLVMType {
ty: Type
}
+/// Metadata describing how the arguments to a native function
+/// should be passed in order to respect the native ABI.
+///
+/// I will do my best to describe this structure, but these
+/// comments are reverse-engineered and may be inaccurate. -NDM
pub struct FnType {
+ /// The LLVM types of each argument. If the cast flag is true,
+ /// then the argument should be cast, typically because the
+ /// official argument type will be an int and the rust type is i8
+ /// or something like that.
arg_tys: ~[LLVMType],
- ret_ty: LLVMType,
- attrs: ~[option::Option<Attribute>],
- sret: bool
-}
-
-impl FnType {
- pub fn decl_fn(&self, decl: &fn(fnty: Type) -> ValueRef) -> ValueRef {
- let atys = self.arg_tys.iter().map(|t| t.ty).collect::<~[Type]>();
- let rty = self.ret_ty.ty;
- let fnty = Type::func(atys, &rty);
- let llfn = decl(fnty);
-
- for (i, a) in self.attrs.iter().enumerate() {
- match *a {
- option::Some(attr) => {
- unsafe {
- let llarg = get_param(llfn, i);
- llvm::LLVMAddAttribute(llarg, attr as c_uint);
- }
- }
- _ => ()
- }
- }
- return llfn;
- }
- pub fn build_shim_args(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef)
- -> ~[ValueRef] {
- let mut atys: &[LLVMType] = self.arg_tys;
- let mut attrs: &[option::Option<Attribute>] = self.attrs;
-
- let mut llargvals = ~[];
- let mut i = 0u;
- let n = arg_tys.len();
-
- if self.sret {
- let llretptr = GEPi(bcx, llargbundle, [0u, n]);
- let llretloc = Load(bcx, llretptr);
- llargvals = ~[llretloc];
- atys = atys.tail();
- attrs = attrs.tail();
- }
-
- while i < n {
- let llargval = if atys[i].cast {
- let arg_ptr = GEPi(bcx, llargbundle, [0u, i]);
- let arg_ptr = BitCast(bcx, arg_ptr, atys[i].ty.ptr_to());
- Load(bcx, arg_ptr)
- } else if attrs[i].is_some() {
- GEPi(bcx, llargbundle, [0u, i])
- } else {
- load_inbounds(bcx, llargbundle, [0u, i])
- };
- llargvals.push(llargval);
- i += 1u;
- }
-
- return llargvals;
- }
-
- pub fn build_shim_ret(&self, bcx: @mut Block, arg_tys: &[Type], ret_def: bool,
- llargbundle: ValueRef, llretval: ValueRef) {
- for (i, a) in self.attrs.iter().enumerate() {
- match *a {
- option::Some(attr) => {
- unsafe {
- llvm::LLVMAddInstrAttribute(llretval, (i + 1u) as c_uint, attr as c_uint);
- }
- }
- _ => ()
- }
- }
- if self.sret || !ret_def {
- return;
- }
- let n = arg_tys.len();
- // R** llretptr = &args->r;
- let llretptr = GEPi(bcx, llargbundle, [0u, n]);
- // R* llretloc = *llretptr; /* (args->r) */
- let llretloc = Load(bcx, llretptr);
- if self.ret_ty.cast {
- let tmp_ptr = BitCast(bcx, llretloc, self.ret_ty.ty.ptr_to());
- // *args->r = r;
- Store(bcx, llretval, tmp_ptr);
- } else {
- // *args->r = r;
- Store(bcx, llretval, llretloc);
- };
- }
-
- pub fn build_wrap_args(&self, bcx: @mut Block, ret_ty: Type,
- llwrapfn: ValueRef, llargbundle: ValueRef) {
- let mut atys: &[LLVMType] = self.arg_tys;
- let mut attrs: &[option::Option<Attribute>] = self.attrs;
- let mut j = 0u;
- let llretptr = if self.sret {
- atys = atys.tail();
- attrs = attrs.tail();
- j = 1u;
- get_param(llwrapfn, 0u)
- } else if self.ret_ty.cast {
- let retptr = alloca(bcx, self.ret_ty.ty, "");
- BitCast(bcx, retptr, ret_ty.ptr_to())
- } else {
- alloca(bcx, ret_ty, "")
- };
+ /// A list of attributes to be attached to each argument (parallel
+ /// the `arg_tys` array). If the attribute for a given is Some,
+ /// then the argument should be passed by reference.
+ attrs: ~[option::Option<Attribute>],
- let mut i = 0u;
- let n = atys.len();
- while i < n {
- let mut argval = get_param(llwrapfn, i + j);
- if attrs[i].is_some() {
- argval = Load(bcx, argval);
- store_inbounds(bcx, argval, llargbundle, [0u, i]);
- } else if atys[i].cast {
- let argptr = GEPi(bcx, llargbundle, [0u, i]);
- let argptr = BitCast(bcx, argptr, atys[i].ty.ptr_to());
- Store(bcx, argval, argptr);
- } else {
- store_inbounds(bcx, argval, llargbundle, [0u, i]);
- }
- i += 1u;
- }
- store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
- }
+ /// LLVM return type.
+ ret_ty: LLVMType,
- pub fn build_wrap_ret(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef) {
- if self.ret_ty.ty.kind() == Void {
- return;
- }
+ /// If true, then an implicit pointer should be added for the result.
+ sret: bool
+}
- if bcx.fcx.llretptr.is_some() {
- let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]);
- let llretval = if self.ret_ty.cast {
- let retptr = BitCast(bcx, llretval, self.ret_ty.ty.ptr_to());
- Load(bcx, retptr)
- } else {
- Load(bcx, llretval)
- };
- let llretptr = BitCast(bcx, bcx.fcx.llretptr.unwrap(), self.ret_ty.ty.ptr_to());
- Store(bcx, llretval, llretptr);
- }
+pub fn compute_abi_info(ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ match ccx.sess.targ_cfg.arch {
+ X86 => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
+ X86_64 => cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def),
+ Arm => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def),
+ Mips => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
}
}
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
-use middle::trans::cabi::{ABIInfo, FnType, LLVMType};
+use middle::trans::cabi::{FnType, LLVMType};
+use middle::trans::context::CrateContext;
use middle::trans::type_::Type;
}
}
-enum ARM_ABIInfo { ARM_ABIInfo }
-
-impl ABIInfo for ARM_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- let mut arg_tys = ~[];
- let mut attrs = ~[];
- for &aty in atys.iter() {
- let (ty, attr) = classify_arg_ty(aty);
- arg_tys.push(ty);
- attrs.push(attr);
- }
-
- let (ret_ty, ret_attr) = if ret_def {
- classify_ret_ty(rty)
- } else {
- (LLVMType { cast: false, ty: Type::void() }, None)
- };
+pub fn compute_abi_info(_ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ let mut arg_tys = ~[];
+ let mut attrs = ~[];
+ for &aty in atys.iter() {
+ let (ty, attr) = classify_arg_ty(aty);
+ arg_tys.push(ty);
+ attrs.push(attr);
+ }
- let mut ret_ty = ret_ty;
+ let (ret_ty, ret_attr) = if ret_def {
+ classify_ret_ty(rty)
+ } else {
+ (LLVMType { cast: false, ty: Type::void() }, None)
+ };
- let sret = ret_attr.is_some();
- if sret {
- arg_tys.unshift(ret_ty);
- attrs.unshift(ret_attr);
- ret_ty = LLVMType { cast: false, ty: Type::void() };
- }
+ let mut ret_ty = ret_ty;
- return FnType {
- arg_tys: arg_tys,
- ret_ty: ret_ty,
- attrs: attrs,
- sret: sret
- };
+ let sret = ret_attr.is_some();
+ if sret {
+ arg_tys.unshift(ret_ty);
+ attrs.unshift(ret_attr);
+ ret_ty = LLVMType { cast: false, ty: Type::void() };
}
-}
-pub fn abi_info() -> @ABIInfo {
- return @ARM_ABIInfo as @ABIInfo;
+ return FnType {
+ arg_tys: arg_tys,
+ ret_ty: ret_ty,
+ attrs: attrs,
+ sret: sret
+ };
}
use std::vec;
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
+use middle::trans::context::CrateContext;
use middle::trans::context::task_llcx;
use middle::trans::cabi::*;
return Type::struct_(fields, false);
}
-enum MIPS_ABIInfo { MIPS_ABIInfo }
-
-impl ABIInfo for MIPS_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- let (ret_ty, ret_attr) = if ret_def {
- classify_ret_ty(rty)
- } else {
- (LLVMType { cast: false, ty: Type::void() }, None)
- };
-
- let mut ret_ty = ret_ty;
-
- let sret = ret_attr.is_some();
- let mut arg_tys = ~[];
- let mut attrs = ~[];
- let mut offset = if sret { 4 } else { 0 };
-
- for aty in atys.iter() {
- let (ty, attr) = classify_arg_ty(*aty, &mut offset);
- arg_tys.push(ty);
- attrs.push(attr);
- };
-
- if sret {
- arg_tys = vec::append(~[ret_ty], arg_tys);
- attrs = vec::append(~[ret_attr], attrs);
- ret_ty = LLVMType { cast: false, ty: Type::void() };
- }
+pub fn compute_abi_info(_ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ let (ret_ty, ret_attr) = if ret_def {
+ classify_ret_ty(rty)
+ } else {
+ (LLVMType { cast: false, ty: Type::void() }, None)
+ };
+
+ let mut ret_ty = ret_ty;
+
+ let sret = ret_attr.is_some();
+ let mut arg_tys = ~[];
+ let mut attrs = ~[];
+ let mut offset = if sret { 4 } else { 0 };
- return FnType {
- arg_tys: arg_tys,
- ret_ty: ret_ty,
- attrs: attrs,
- sret: sret
- };
+ for aty in atys.iter() {
+ let (ty, attr) = classify_arg_ty(*aty, &mut offset);
+ arg_tys.push(ty);
+ attrs.push(attr);
+ };
+
+ if sret {
+ arg_tys = vec::append(~[ret_ty], arg_tys);
+ attrs = vec::append(~[ret_attr], attrs);
+ ret_ty = LLVMType { cast: false, ty: Type::void() };
}
-}
-pub fn abi_info() -> @ABIInfo {
- return @MIPS_ABIInfo as @ABIInfo;
+ return FnType {
+ arg_tys: arg_tys,
+ ret_ty: ret_ty,
+ attrs: attrs,
+ sret: sret
+ };
}
use super::cabi::*;
use super::common::*;
use super::machine::*;
-
use middle::trans::type_::Type;
-struct X86_ABIInfo {
- ccx: @mut CrateContext
-}
+pub fn compute_abi_info(ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ let mut arg_tys = ~[];
+ let mut attrs = ~[];
-impl ABIInfo for X86_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- let mut arg_tys = do atys.map |a| {
- LLVMType { cast: false, ty: *a }
- };
- let mut ret_ty = LLVMType {
+ let ret_ty;
+ let sret;
+ if !ret_def {
+ ret_ty = LLVMType {
cast: false,
- ty: rty
+ ty: Type::void(),
};
- let mut attrs = do atys.map |_| {
- None
- };
-
- // Rules for returning structs taken from
+ sret = false;
+ } else if rty.kind() == Struct {
+ // Returning a structure. Most often, this will use
+ // a hidden first argument. On some platforms, though,
+ // small structs are returned as integers.
+ //
+ // Some links:
// http://www.angelcode.com/dev/callconv/callconv.html
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
- let sret = {
- let returning_a_struct = rty.kind() == Struct && ret_def;
- let big_struct = match self.ccx.sess.targ_cfg.os {
- os_win32 | os_macos => llsize_of_alloc(self.ccx, rty) > 8,
- _ => true
- };
- returning_a_struct && big_struct
+
+ enum Strategy { RetValue(Type), RetPointer }
+ let strategy = match ccx.sess.targ_cfg.os {
+ os_win32 | os_macos => {
+ match llsize_of_alloc(ccx, rty) {
+ 1 => RetValue(Type::i8()),
+ 2 => RetValue(Type::i16()),
+ 4 => RetValue(Type::i32()),
+ 8 => RetValue(Type::i64()),
+ _ => RetPointer
+ }
+ }
+ _ => {
+ RetPointer
+ }
};
- if sret {
- let ret_ptr_ty = LLVMType {
- cast: false,
- ty: ret_ty.ty.ptr_to()
- };
- arg_tys = ~[ret_ptr_ty] + arg_tys;
- attrs = ~[Some(StructRetAttribute)] + attrs;
- ret_ty = LLVMType {
- cast: false,
- ty: Type::void(),
- };
- } else if !ret_def {
- ret_ty = LLVMType {
- cast: false,
- ty: Type::void()
- };
- }
+ match strategy {
+ RetValue(t) => {
+ ret_ty = LLVMType {
+ cast: true,
+ ty: t
+ };
+ sret = false;
+ }
+ RetPointer => {
+ arg_tys.push(LLVMType {
+ cast: false,
+ ty: rty.ptr_to()
+ });
+ attrs.push(Some(StructRetAttribute));
- return FnType {
- arg_tys: arg_tys,
- ret_ty: ret_ty,
- attrs: attrs,
- sret: sret
+ ret_ty = LLVMType {
+ cast: false,
+ ty: Type::void(),
+ };
+ sret = true;
+ }
+ }
+ } else {
+ ret_ty = LLVMType {
+ cast: false,
+ ty: rty
};
+ sret = false;
+ }
+
+ for &a in atys.iter() {
+ arg_tys.push(LLVMType { cast: false, ty: a });
+ attrs.push(None);
}
-}
-pub fn abi_info(ccx: @mut CrateContext) -> @ABIInfo {
- return @X86_ABIInfo {
- ccx: ccx
- } as @ABIInfo;
+ return FnType {
+ arg_tys: arg_tys,
+ ret_ty: ret_ty,
+ attrs: attrs,
+ sret: sret
+ };
}
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute, ByValAttribute};
use middle::trans::cabi::*;
+use middle::trans::context::CrateContext;
use middle::trans::type_::Type;
return Type::struct_(tys, false);
}
-fn x86_64_tys(atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
-
+pub fn compute_abi_info(_ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
fn x86_64_ty(ty: Type,
is_mem_cls: &fn(cls: &[RegClass]) -> bool,
attr: Attribute) -> (LLVMType, Option<Attribute>) {
sret: sret
};
}
-
-enum X86_64_ABIInfo { X86_64_ABIInfo }
-
-impl ABIInfo for X86_64_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- return x86_64_tys(atys, rty, ret_def);
- }
-}
-
-pub fn abi_info() -> @ABIInfo {
- return @X86_64_ABIInfo as @ABIInfo;
-}
use middle::trans::meth;
use middle::trans::monomorphize;
use middle::trans::type_of;
+use middle::trans::foreign;
use middle::ty;
use middle::subst::Subst;
use middle::typeck;
use middle::trans::type_::Type;
use syntax::ast;
+use syntax::abi::AbiSet;
use syntax::ast_map;
use syntax::visit;
use syntax::visit::Visitor;
type_params: &[ty::t], // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
-> FnData {
- //!
- //
- // Translates a reference to a fn/method item, monomorphizing and
- // inlining as it goes.
- //
- // # Parameters
- //
- // - `bcx`: the current block where the reference to the fn occurs
- // - `def_id`: def id of the fn or method item being referenced
- // - `ref_id`: node id of the reference to the fn/method, if applicable.
- // This parameter may be zero; but, if so, the resulting value may not
- // have the right type, so it must be cast before being used.
- // - `type_params`: values for each of the fn/method's type parameters
- // - `vtables`: values for each bound on each of the type parameters
+ /*!
+ * Translates a reference to a fn/method item, monomorphizing and
+ * inlining as it goes.
+ *
+ * # Parameters
+ *
+ * - `bcx`: the current block where the reference to the fn occurs
+ * - `def_id`: def id of the fn or method item being referenced
+ * - `ref_id`: node id of the reference to the fn/method, if applicable.
+ * This parameter may be zero; but, if so, the resulting value may not
+ * have the right type, so it must be cast before being used.
+ * - `type_params`: values for each of the fn/method's type parameters
+ * - `vtables`: values for each bound on each of the type parameters
+ */
let _icx = push_ctxt("trans_fn_ref_with_vtables");
let ccx = bcx.ccx();
}
// Find the actual function pointer.
- let val = {
+ let mut val = {
if def_id.crate == ast::LOCAL_CRATE {
// Internal reference.
get_item_val(ccx, def_id.node)
}
};
+ // This is subtle and surprising, but sometimes we have to bitcast
+ // the resulting fn pointer. The reason has to do with external
+ // functions. If you have two crates that both bind the same C
+ // library, they may not use precisely the same types: for
+ // example, they will probably each declare their own structs,
+ // which are distinct types from LLVM's point of view (nominal
+ // types).
+ //
+ // Now, if those two crates are linked into an application, and
+ // they contain inlined code, you can wind up with a situation
+ // where both of those functions wind up being loaded into this
+ // application simultaneously. In that case, the same function
+ // (from LLVM's point of view) requires two types. But of course
+ // LLVM won't allow one function to have two types.
+ //
+ // What we currently do, therefore, is declare the function with
+ // one of the two types (whichever happens to come first) and then
+ // bitcast as needed when the function is referenced to make sure
+ // it has the type we expect.
+ //
+ // This can occur on either a crate-local or crate-external
+ // reference. It also occurs when testing libcore and in some
+ // other weird situations. Annoying.
+ let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
+ let llptrty = llty.ptr_to();
+ if val_ty(val) != llptrty {
+ val = BitCast(bcx, val, llptrty);
+ }
+
return FnData {llfn: val};
}
*cx
}
-// See [Note-arg-mode]
pub fn trans_call_inner(in_cx: @mut Block,
call_info: Option<NodeInfo>,
- fn_expr_ty: ty::t,
+ callee_ty: ty::t,
ret_ty: ty::t,
get_callee: &fn(@mut Block) -> Callee,
args: CallArgs,
dest: Option<expr::Dest>,
autoref_arg: AutorefArg)
-> Result {
+ /*!
+ * This behemoth of a function translates function calls.
+ * Unfortunately, in order to generate more efficient LLVM
+ * output at -O0, it has quite a complex signature (refactoring
+ * this into two functions seems like a good idea).
+ *
+ * In particular, for lang items, it is invoked with a dest of
+ * None, and
+ */
+
+
do base::with_scope_result(in_cx, call_info, "call") |cx| {
let callee = get_callee(cx);
let mut bcx = callee.bcx;
}
};
- let llretslot = trans_ret_slot(bcx, fn_expr_ty, dest);
+ let abi = match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref f) => f.abis,
+ _ => AbiSet::Rust()
+ };
+ let is_rust_fn =
+ abi.is_rust() ||
+ abi.is_intrinsic();
+
+ // Generate a location to store the result. If the user does
+ // not care about the result, just make a stack slot.
+ let opt_llretslot = match dest {
+ None => {
+ assert!(!type_of::return_uses_outptr(in_cx.tcx(), ret_ty));
+ None
+ }
+ Some(expr::SaveIn(dst)) => Some(dst),
+ Some(expr::Ignore) => {
+ if !ty::type_is_voidish(ret_ty) {
+ Some(alloc_ty(bcx, ret_ty, "__llret"))
+ } else {
+ unsafe {
+ Some(llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()))
+ }
+ }
+ }
+ };
- let mut llargs = ~[];
+ let mut llresult = unsafe {
+ llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
+ };
- if !ty::type_is_immediate(bcx.tcx(), ret_ty) {
- llargs.push(llretslot);
- }
+ // The code below invokes the function, using either the Rust
+ // conventions (if it is a rust fn) or the native conventions
+ // (otherwise). The important part is that, when all is sad
+ // and done, either the return value of the function will have been
+ // written in opt_llretslot (if it is Some) or `llresult` will be
+ // set appropriately (otherwise).
+ if is_rust_fn {
+ let mut llargs = ~[];
+
+ // Push the out-pointer if we use an out-pointer for this
+ // return type, otherwise push "undef".
+ if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
+ llargs.push(opt_llretslot.unwrap());
+ }
+
+ // Push the environment.
+ llargs.push(llenv);
- llargs.push(llenv);
- bcx = trans_args(bcx, args, fn_expr_ty, autoref_arg, &mut llargs);
+ // Push the arguments.
+ bcx = trans_args(bcx, args, callee_ty,
+ autoref_arg, &mut llargs);
- // Now that the arguments have finished evaluating, we need to revoke
- // the cleanup for the self argument
- match callee.data {
- Method(d) => {
- for &v in d.temp_cleanup.iter() {
- revoke_clean(bcx, v);
+ // Now that the arguments have finished evaluating, we
+ // need to revoke the cleanup for the self argument
+ match callee.data {
+ Method(d) => {
+ for &v in d.temp_cleanup.iter() {
+ revoke_clean(bcx, v);
+ }
}
+ _ => {}
}
- _ => {}
- }
- // Uncomment this to debug calls.
- /*
- printfln!("calling: %s", bcx.val_to_str(llfn));
- for llarg in llargs.iter() {
- printfln!("arg: %s", bcx.val_to_str(*llarg));
+ // Invoke the actual rust fn and update bcx/llresult.
+ let (llret, b) = base::invoke(bcx, llfn, llargs);
+ bcx = b;
+ llresult = llret;
+
+ // If the Rust convention for this type is return via
+ // the return value, copy it into llretslot.
+ match opt_llretslot {
+ Some(llretslot) => {
+ if !type_of::return_uses_outptr(bcx.tcx(), ret_ty) &&
+ !ty::type_is_voidish(ret_ty)
+ {
+ Store(bcx, llret, llretslot);
+ }
+ }
+ None => {}
+ }
+ } else {
+ // Lang items are the only case where dest is None, and
+ // they are always Rust fns.
+ assert!(dest.is_some());
+
+ let mut llargs = ~[];
+ bcx = trans_args(bcx, args, callee_ty,
+ autoref_arg, &mut llargs);
+ bcx = foreign::trans_native_call(bcx, callee_ty,
+ llfn, opt_llretslot.unwrap(), llargs);
}
- io::println("---");
- */
-
- // If the block is terminated, then one or more of the args
- // has type _|_. Since that means it diverges, the code for
- // the call itself is unreachable.
- let (llresult, new_bcx) = base::invoke(bcx, llfn, llargs);
- bcx = new_bcx;
+ // If the caller doesn't care about the result of this fn call,
+ // drop the temporary slot we made.
match dest {
- None => { assert!(ty::type_is_immediate(bcx.tcx(), ret_ty)) }
+ None => {
+ assert!(!type_of::return_uses_outptr(bcx.tcx(), ret_ty));
+ }
Some(expr::Ignore) => {
// drop the value if it is not being saved.
- if ty::type_needs_drop(bcx.tcx(), ret_ty) {
- if ty::type_is_immediate(bcx.tcx(), ret_ty) {
- let llscratchptr = alloc_ty(bcx, ret_ty, "__ret");
- Store(bcx, llresult, llscratchptr);
- bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
- } else {
- bcx = glue::drop_ty(bcx, llretslot, ret_ty);
- }
- }
- }
- Some(expr::SaveIn(lldest)) => {
- // If this is an immediate, store into the result location.
- // (If this was not an immediate, the result will already be
- // directly written into the output slot.)
- if ty::type_is_immediate(bcx.tcx(), ret_ty) {
- Store(bcx, llresult, lldest);
- }
+ bcx = glue::drop_ty(bcx, opt_llretslot.unwrap(), ret_ty);
}
+ Some(expr::SaveIn(_)) => { }
}
if ty::type_is_bot(ret_ty) {
Unreachable(bcx);
}
+
rslt(bcx, llresult)
}
}
-
pub enum CallArgs<'self> {
ArgExprs(&'self [@ast::expr]),
ArgVals(&'self [ValueRef])
}
-pub fn trans_ret_slot(bcx: @mut Block, fn_ty: ty::t, dest: Option<expr::Dest>)
- -> ValueRef {
- let retty = ty::ty_fn_ret(fn_ty);
-
- match dest {
- Some(expr::SaveIn(dst)) => dst,
- _ => {
- if ty::type_is_immediate(bcx.tcx(), retty) {
- unsafe {
- llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
- }
- } else {
- alloc_ty(bcx, retty, "__trans_ret_slot")
- }
- }
- }
-}
-
pub fn trans_args(cx: @mut Block,
args: CallArgs,
fn_ty: ty::t,
if formal_arg_ty != arg_datum.ty {
// this could happen due to e.g. subtyping
- let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, &formal_arg_ty);
+ let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
debug!("casting actual type (%s) to match formal (%s)",
bcx.val_to_str(val), bcx.llty_str(llformal_arg_ty));
val = PointerCast(bcx, val, llformal_arg_ty);
use std::cast::transmute;
use std::cast;
use std::hashmap::{HashMap};
-use std::libc::{c_uint, c_longlong, c_ulonglong};
+use std::libc::{c_uint, c_longlong, c_ulonglong, c_char};
use std::vec;
use syntax::ast::ident;
use syntax::ast_map::{path, path_elt};
}
}
-pub type ExternMap = HashMap<@str, ValueRef>;
+pub type ExternMap = HashMap<~str, ValueRef>;
// Types used for llself.
pub struct ValSelfData {
// outputting the resume instruction.
personality: Option<ValueRef>,
- // True if this function has an immediate return value, false otherwise.
- // If this is false, the llretptr will alias the first argument of the
- // function.
- has_immediate_return_value: bool,
+ // True if the caller expects this fn to use the out pointer to
+ // return. Either way, your code should write into llretptr, but if
+ // this value is false, llretptr will be a local alloca.
+ caller_expects_out_pointer: bool,
// Maps arguments to allocas created for them in llallocas.
llargs: @mut HashMap<ast::NodeId, ValueRef>,
impl FunctionContext {
pub fn arg_pos(&self, arg: uint) -> uint {
- if self.has_immediate_return_value {
- arg + 1u
- } else {
+ if self.caller_expects_out_pointer {
arg + 2u
+ } else {
+ arg + 1u
}
}
pub fn out_arg_pos(&self) -> uint {
- assert!(!self.has_immediate_return_value);
+ assert!(self.caller_expects_out_pointer);
0u
}
pub fn env_arg_pos(&self) -> uint {
- if !self.has_immediate_return_value {
+ if self.caller_expects_out_pointer {
1u
} else {
0u
pub fn C_floating(s: &str, t: Type) -> ValueRef {
unsafe {
- do s.to_c_str().with_ref |buf| {
+ do s.with_c_str |buf| {
llvm::LLVMConstRealOfString(t.to_ref(), buf)
}
}
None => ()
}
- let sc = do s.to_c_str().with_ref |buf| {
- llvm::LLVMConstStringInContext(cx.llcx, buf, s.len() as c_uint, False)
+ let sc = do s.as_imm_buf |buf, buflen| {
+ llvm::LLVMConstStringInContext(cx.llcx, buf as *c_char, buflen as c_uint, False)
};
let gsym = token::gensym("str");
- let g = do fmt!("str%u", gsym).to_c_str().with_ref |buf| {
+ let g = do fmt!("str%u", gsym).with_c_str |buf| {
llvm::LLVMAddGlobal(cx.llmod, val_ty(sc).to_ref(), buf)
};
llvm::LLVMSetInitializer(g, sc);
use std::c_str::ToCStr;
use std::libc::c_uint;
+use std::vec;
use syntax::{ast, ast_util, ast_map};
pub fn const_lit(cx: &mut CrateContext, e: &ast::expr, lit: ast::lit)
fn const_addr_of(cx: &mut CrateContext, cv: ValueRef) -> ValueRef {
unsafe {
- let gv = do "const".to_c_str().with_ref |name| {
+ let gv = do "const".with_c_str |name| {
llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
};
llvm::LLVMSetInitializer(gv, cv);
ast::expr_vec(ref es, ast::m_imm) => {
let (cv, sz, llunitty) = const_vec(cx, e, *es);
let llty = val_ty(cv);
- let gv = do "const".to_c_str().with_ref |name| {
+ let gv = do "const".with_c_str |name| {
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
};
llvm::LLVMSetInitializer(gv, cv);
_ => cx.sess.span_bug(e.span, "bad const-slice expr")
}
}
+ ast::expr_repeat(elem, count, _) => {
+ let vec_ty = ty::expr_ty(cx.tcx, e);
+ let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
+ let llunitty = type_of::type_of(cx, unit_ty);
+ let n = match const_eval::eval_const_expr(cx.tcx, count) {
+ const_eval::const_int(i) => i as uint,
+ const_eval::const_uint(i) => i as uint,
+ _ => cx.sess.span_bug(count.span, "count must be integral const expression.")
+ };
+ let vs = vec::from_elem(n, const_expr(cx, elem));
+ let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
+ C_struct(vs)
+ } else {
+ C_array(llunitty, vs)
+ };
+ v
+ }
ast::expr_path(ref pth) => {
assert_eq!(pth.types.len(), 0);
let tcx = cx.tcx;
unsafe {
let llcx = llvm::LLVMContextCreate();
set_task_llcx(llcx);
- let llmod = do name.to_c_str().with_ref |buf| {
+ let llmod = do name.with_c_str |buf| {
llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
};
let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
- do data_layout.to_c_str().with_ref |buf| {
+ do data_layout.with_c_str |buf| {
llvm::LLVMSetDataLayout(llmod, buf)
};
- do targ_triple.to_c_str().with_ref |buf| {
+ do targ_triple.with_c_str |buf| {
llvm::LLVMSetTarget(llmod, buf)
};
let targ_cfg = sess.targ_cfg;
ccx, modpath, "loglevel");
let global;
unsafe {
- global = do s.to_c_str().with_ref |buf| {
+ global = do s.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
};
llvm::LLVMSetGlobalConstant(global, False);
pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode {
/*!
- *
- * Indicates the "appropriate" mode for this value,
- * which is either by ref or by value, depending
- * on whether type is immediate or not. */
+ * Indicates the "appropriate" mode for this value,
+ * which is either by ref or by value, depending
+ * on whether type is immediate or not.
+ */
- if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
+ if ty::type_is_voidish(ty) {
ByValue
} else if ty::type_is_immediate(tcx, ty) {
ByValue
let _icx = push_ctxt("copy_to");
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
return bcx;
}
debug!("move_to(self=%s, action=%?, dst=%s)",
self.to_str(bcx.ccx()), action, bcx.val_to_str(dst));
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
return bcx;
}
*
* Yields the value itself. */
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
C_nil()
} else {
match self.mode {
match self.mode {
ByRef(_) => self.val,
ByValue => {
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to())
} else {
let slot = alloc_ty(bcx, self.ty, "");
use driver::session;
use lib::llvm::llvm;
-use lib::llvm::{ModuleRef, ContextRef};
+use lib::llvm::{ModuleRef, ContextRef, ValueRef};
use lib::llvm::debuginfo::*;
use middle::trans::common::*;
use middle::trans::machine;
use std::ptr;
use std::vec;
use syntax::codemap::span;
-use syntax::{ast, codemap, ast_util, ast_map};
+use syntax::{ast, codemap, ast_util, ast_map, opt_vec};
+use syntax::parse::token::special_idents;
static DW_LANG_RUST: int = 0x9000;
priv builder: DIBuilderRef,
priv curr_loc: (uint, uint),
priv created_files: HashMap<~str, DIFile>,
- priv created_functions: HashMap<ast::NodeId, DISubprogram>,
+ priv created_functions: HashMap<FunctionCacheKey, DISubprogram>,
priv created_blocks: HashMap<ast::NodeId, DILexicalBlock>,
priv created_types: HashMap<uint, DIType>
}
}
}
+#[deriving(Eq,IterBytes)]
+struct FunctionCacheKey {
+ // Use the address of the llvm function (FunctionContext::llfn) as key for the cache. This
+ // nicely takes care of monomorphization, where two specializations will have the same
+ // ast::NodeId but different llvm functions (each needing its own debug description).
+ priv llfn: ValueRef
+}
+
+impl FunctionCacheKey {
+ fn for_function_context(fcx: &FunctionContext) -> FunctionCacheKey {
+ FunctionCacheKey { llfn: fcx.llfn }
+ }
+}
pub struct FunctionDebugContext {
priv scope_map: HashMap<ast::NodeId, DIScope>,
priv argument_counter: uint,
}
-impl FunctionDebugContext {
- fn new() -> FunctionDebugContext {
- return FunctionDebugContext {
- scope_map: HashMap::new(),
- argument_counter: 1,
- };
- }
-}
-
/// Create any deferred debug metadata nodes
pub fn finalize(cx: @mut CrateContext) {
debug!("finalize");
}
}
+/// Creates debug information for a local variable introduced in the head of a match-statement arm.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_match_binding_metadata(bcx: @mut Block,
variable_ident: ast::ident,
node_id: ast::NodeId,
declare_local(bcx, variable_ident, node_id, variable_type, span);
}
+/// Creates debug information for the self argument of a method.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_self_argument_metadata(bcx: @mut Block,
+ variable_type: ty::t,
+ llptr: ValueRef) {
+ assert_fcx_has_span(bcx.fcx);
+ let span = bcx.fcx.span.unwrap();
+
+ let cx = bcx.ccx();
+
+ let filename = span_start(cx, span).file.name;
+ let file_metadata = file_metadata(cx, filename);
+
+ let loc = span_start(cx, span);
+ let type_metadata = type_metadata(cx, variable_type, span);
+ let scope = create_function_metadata(bcx.fcx);
+
+ let var_metadata = do cx.sess.str_of(special_idents::self_).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateLocalVariable(
+ DIB(cx),
+ DW_TAG_arg_variable,
+ scope,
+ name,
+ file_metadata,
+ loc.line as c_uint,
+ type_metadata,
+ false,
+ 0,
+ 1)
+ }
+ };
+
+ set_debug_location(cx, scope, loc.line, loc.col.to_uint());
+ unsafe {
+ let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
+ DIB(cx),
+ llptr,
+ var_metadata,
+ bcx.llbb);
+
+ llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
+ }
+}
+
/// Creates debug information for the given function argument.
///
/// Adds the created metadata nodes directly to the crate's IR.
argument_index as c_uint
};
- let arg_metadata = do name.to_c_str().with_ref |name| {
+ let arg_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
}
}
-/// Sets the current debug location at the beginning of the span
+/// Sets the current debug location at the beginning of the span.
///
-/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...)
+/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). The node_id parameter is used to
+/// reliably find the correct visibility scope for the code position.
pub fn update_source_pos(fcx: &FunctionContext,
node_id: ast::NodeId,
span: span) {
/// The return value should be ignored if called from outside of the debuginfo module.
pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
let cx = fcx.ccx;
+ let cache_key = FunctionCacheKey::for_function_context(fcx);
+
+ match dbg_cx(cx).created_functions.find_copy(&cache_key) {
+ Some(fn_metadata) => {
+ assert!(fcx.debug_context.is_some());
+ return fn_metadata;
+ }
+ None => { /* fallthrough */}
+ }
+
+ let empty_generics = ast::Generics { lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty };
let fnitem = cx.tcx.items.get_copy(&fcx.id);
- let (ident, fn_decl, id) = match fnitem {
+ let (ident, fn_decl, generics, span) = match fnitem {
ast_map::node_item(ref item, _) => {
match item.node {
- ast::item_fn(ref fn_decl, _, _, _, _) => {
- (item.ident, fn_decl, item.id)
+ ast::item_fn(ref fn_decl, _, _, ref generics, _) => {
+ (item.ident, fn_decl, generics, item.span)
}
_ => fcx.ccx.sess.span_bug(item.span,
"create_function_metadata: item bound to non-function")
ast_map::node_method(
@ast::method {
decl: ref fn_decl,
- id: id,
ident: ident,
+ generics: ref generics,
+ span: span,
_
},
_,
_) => {
- (ident, fn_decl, id)
+ (ident, fn_decl, generics, span)
}
ast_map::node_expr(ref expr) => {
match expr.node {
ast::expr_fn_block(ref fn_decl, _) => {
let name = gensym_name("fn");
- (name, fn_decl, expr.id)
+ (name, fn_decl,
+ // This is not quite right. It should actually inherit the generics of the
+ // enclosing function.
+ &empty_generics,
+ expr.span)
}
_ => fcx.ccx.sess.span_bug(expr.span,
"create_function_metadata: expected an expr_fn_block here")
@ast::provided(
@ast::method {
decl: ref fn_decl,
- id: id,
ident: ident,
+ generics: ref generics,
+ span: span,
_
}),
_,
_) => {
- (ident, fn_decl, id)
+ (ident, fn_decl, generics, span)
}
_ => fcx.ccx.sess.bug(fmt!("create_function_metadata: unexpected sort of node: %?", fnitem))
};
- match dbg_cx(cx).created_functions.find_copy(&id) {
- Some(fn_metadata) => return fn_metadata,
- None => ()
- }
-
- let span = match fcx.span {
- Some(value) => value,
- None => codemap::dummy_sp()
- };
-
debug!("create_function_metadata: %s, %s",
cx.sess.str_of(ident),
cx.sess.codemap.span_to_str(span));
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
- let return_type_metadata = if cx.sess.opts.extra_debuginfo {
- match fn_decl.output.node {
- ast::ty_nil => ptr::null(),
- _ => type_metadata(cx, ty::node_id_to_type(cx.tcx, id), fn_decl.output.span)
- }
- } else {
- ptr::null()
+ let function_type_metadata = unsafe {
+ let fn_signature = get_function_signature(fcx, fn_decl);
+ llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
};
- let fn_ty = unsafe {
- llvm::LLVMDIBuilderCreateSubroutineType(
- DIB(cx),
- file_metadata,
- create_DIArray(DIB(cx), [return_type_metadata]))
+ // get_template_parameters() will append a `<...>` clause to the function name if necessary.
+ let mut function_name = cx.sess.str_of(ident).to_owned();
+ let template_parameters = get_template_parameters(fcx,
+ generics,
+ file_metadata,
+ &mut function_name);
+
+ let fn_metadata = do function_name.to_c_str().with_ref |function_name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateFunction(
+ DIB(cx),
+ file_metadata,
+ function_name,
+ function_name,
+ file_metadata,
+ loc.line as c_uint,
+ function_type_metadata,
+ false,
+ true,
+ loc.line as c_uint,
+ FlagPrototyped as c_uint,
+ cx.sess.opts.optimize != session::No,
+ fcx.llfn,
+ template_parameters,
+ ptr::null())
+ }
};
- let fn_metadata =
- do cx.sess.str_of(ident).to_c_str().with_ref |name| {
- do cx.sess.str_of(ident).to_c_str().with_ref |linkage| {
- unsafe {
- llvm::LLVMDIBuilderCreateFunction(
- DIB(cx),
- file_metadata,
- name,
- linkage,
- file_metadata,
- loc.line as c_uint,
- fn_ty,
- false,
- true,
- loc.line as c_uint,
- FlagPrototyped as c_uint,
- cx.sess.opts.optimize != session::No,
- fcx.llfn,
- ptr::null(),
- ptr::null())
+ dbg_cx(cx).created_functions.insert(cache_key, fn_metadata);
+
+ // Initialize fn debug context (including scope map)
+ {
+ assert!(fcx.debug_context.is_none());
+
+ let mut fn_debug_context = ~FunctionDebugContext {
+ scope_map: HashMap::new(),
+ argument_counter: if fcx.llself.is_some() { 2 } else { 1 }
+ };
+
+ let entry_block_id = fcx.entry_bcx.get_ref().node_info.get_ref().id;
+ let entry_block = cx.tcx.items.get(&entry_block_id);
+
+ match *entry_block {
+ ast_map::node_block(ref block) => {
+ let scope_map = &mut fn_debug_context.scope_map;
+ let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
+
+ populate_scope_map(cx, arg_pats, block, fn_metadata, scope_map);
}
- }};
+ _ => cx.sess.span_bug(span,
+ fmt!("debuginfo::create_function_metadata() - \
+ FunctionContext::entry_bcx::node_info points to wrong type of ast_map \
+ entry. Expected: ast_map::node_block, actual: %?", *entry_block))
+ }
+
+ fcx.debug_context = Some(fn_debug_context);
+ }
+
+ return fn_metadata;
- assert!(fcx.debug_context.is_none());
+ fn get_function_signature(fcx: &FunctionContext, fn_decl: &ast::fn_decl) -> DIArray {
+ let cx = fcx.ccx;
- let mut fn_debug_context = ~FunctionDebugContext::new();
- let entry_block_id = fcx.entry_bcx.get_ref().node_info.get_ref().id;
- let entry_block = cx.tcx.items.get(&entry_block_id);
+ if !cx.sess.opts.extra_debuginfo {
+ return create_DIArray(DIB(cx), []);
+ }
+
+ let mut signature = vec::with_capacity(fn_decl.inputs.len() + 1);
- match *entry_block {
- ast_map::node_block(ref block) => {
- let scope_map = &mut fn_debug_context.scope_map;
- let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
+ // Return type -- llvm::DIBuilder wants this at index 0
+ match fn_decl.output.node {
+ ast::ty_nil => {
+ signature.push(ptr::null());
+ }
+ _ => {
+ let return_type = ty::node_id_to_type(cx.tcx, fcx.id);
+ let return_type = match fcx.param_substs {
+ None => return_type,
+ Some(substs) => {
+ ty::subst_tps(cx.tcx, substs.tys, substs.self_ty, return_type)
+ }
+ };
- populate_scope_map(cx, arg_pats, block, fn_metadata, scope_map);
+ signature.push(type_metadata(cx, return_type, codemap::dummy_sp()));
+ }
}
- _ => cx.sess.span_bug(span,
- fmt!("debuginfo::create_function_metadata() - \
- FunctionContext::entry_bcx::node_info points to wrong type of ast_map entry. \
- Expected: ast_map::node_block, actual: %?", *entry_block))
+
+ // arguments types
+ for arg in fn_decl.inputs.iter() {
+ let arg_type = ty::node_id_to_type(cx.tcx, arg.pat.id);
+ let arg_type = match fcx.param_substs {
+ None => arg_type,
+ Some(substs) => {
+ ty::subst_tps(cx.tcx, substs.tys, substs.self_ty, arg_type)
+ }
+ };
+
+ signature.push(type_metadata(cx, arg_type, codemap::dummy_sp()));
+ }
+
+ return create_DIArray(DIB(cx), signature);
}
- fcx.debug_context = Some(fn_debug_context);
+ fn get_template_parameters(fcx: &FunctionContext,
+ generics: &ast::Generics,
+ file_metadata: DIFile,
+ name_to_append_suffix_to: &mut ~str)
+ -> DIArray {
+ let cx = fcx.ccx;
- dbg_cx(cx).created_functions.insert(id, fn_metadata);
- return fn_metadata;
+ let self_type = match fcx.param_substs {
+ Some(@param_substs{ self_ty: self_type, _ }) => self_type,
+ _ => None
+ };
+
+ // Only true for static default methods:
+ let has_self_type = self_type.is_some();
+
+ if !generics.is_type_parameterized() && !has_self_type {
+ return ptr::null();
+ }
+
+ name_to_append_suffix_to.push_char('<');
+
+ // The list to be filled with template parameters:
+ let mut template_params: ~[DIDescriptor] = vec::with_capacity(generics.ty_params.len() + 1);
+
+ // Handle self type
+ if has_self_type {
+ let actual_self_type = self_type.unwrap();
+ let actual_self_type_metadata = type_metadata(cx,
+ actual_self_type,
+ codemap::dummy_sp());
+
+ // Add self type name to <...> clause of function name
+ let actual_self_type_name = ty_to_str(cx.tcx, actual_self_type);
+ name_to_append_suffix_to.push_str(actual_self_type_name);
+ if generics.is_type_parameterized() {
+ name_to_append_suffix_to.push_str(",");
+ }
+
+ let ident = special_idents::type_self;
+
+ let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name,
+ actual_self_type_metadata,
+ ptr::null(),
+ 0,
+ 0)
+ }
+ };
+
+ template_params.push(param_metadata);
+ }
+
+ // Handle other generic parameters
+ let actual_types = match fcx.param_substs {
+ Some(@param_substs { tys: ref types, _ }) => types,
+ None => {
+ return create_DIArray(DIB(cx), template_params);
+ }
+ };
+
+ for (index, &ast::TyParam{ ident: ident, _ }) in generics.ty_params.iter().enumerate() {
+ let actual_type = actual_types[index];
+ let actual_type_metadata = type_metadata(cx, actual_type, codemap::dummy_sp());
+
+ // Add actual type name to <...> clause of function name
+ let actual_type_name = ty_to_str(cx.tcx, actual_type);
+ name_to_append_suffix_to.push_str(actual_type_name);
+
+ if index != generics.ty_params.len() - 1 {
+ name_to_append_suffix_to.push_str(",");
+ }
+
+ let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name,
+ actual_type_metadata,
+ ptr::null(),
+ 0,
+ 0)
+ }
+ };
+
+ template_params.push(param_metadata);
+ }
+
+ name_to_append_suffix_to.push_char('>');
+
+ return create_DIArray(DIB(cx), template_params);
+ }
}
let work_dir = cx.sess.working_dir.to_str();
let producer = fmt!("rustc version %s", env!("CFG_VERSION"));
- do crate_name.to_c_str().with_ref |crate_name| {
- do work_dir.to_c_str().with_ref |work_dir| {
- do producer.to_c_str().with_ref |producer| {
- do "".to_c_str().with_ref |flags| {
- do "".to_c_str().with_ref |split_name| {
+ do crate_name.with_c_str |crate_name| {
+ do work_dir.with_c_str |work_dir| {
+ do producer.with_c_str |producer| {
+ do "".with_c_str |flags| {
+ do "".with_c_str |split_name| {
unsafe {
llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder,
DW_LANG_RUST as c_uint, crate_name, work_dir, producer,
let type_metadata = type_metadata(cx, variable_type, span);
let scope = scope_metadata(bcx.fcx, node_id, span);
- let var_metadata = do name.to_c_str().with_ref |name| {
+ let var_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
};
let file_metadata =
- do file_name.to_c_str().with_ref |file_name| {
- do work_dir.to_c_str().with_ref |work_dir| {
+ do file_name.with_c_str |file_name| {
+ do work_dir.with_c_str |work_dir| {
unsafe {
llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
}
let llvm_type = type_of::type_of(cx, t);
let (size, align) = size_and_align_of(cx, llvm_type);
- let ty_metadata = do name.to_c_str().with_ref |name| {
+ let ty_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateBasicType(
DIB(cx),
let pointer_llvm_type = type_of::type_of(cx, pointer_type);
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
let name = ty_to_str(cx.tcx, pointer_type);
- let ptr_metadata = do name.to_c_str().with_ref |name| {
+ let ptr_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreatePointerType(
DIB(cx),
let struct_llvm_type = type_of::type_of(cx, struct_type);
let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) };
- let field_names = do fields.map |field| { cx.sess.str_of(field.ident).to_owned() };
+ let field_names = do fields.map |field| {
+ if field.ident == special_idents::unnamed_field {
+ ~""
+ } else {
+ cx.sess.str_of(field.ident).to_owned()
+ }
+ };
let field_types_metadata = do fields.map |field| {
type_metadata(cx, field.mt.ty, span)
};
let name: &str = cx.sess.str_of(v.name);
let discriminant_value = v.disr_val as c_ulonglong;
- do name.to_c_str().with_ref |name| {
+ do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateEnumerator(
DIB(cx),
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
- let discriminant_type_metadata = do enum_name.to_c_str().with_ref |enum_name| {
+ let discriminant_type_metadata = do enum_name.with_c_str |enum_name| {
unsafe {
llvm::LLVMDIBuilderCreateEnumerationType(
DIB(cx),
Some(discriminant_type_metadata),
span);
- do "".to_c_str().with_ref |name| {
+ do "".with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
let enum_llvm_type = type_of::type_of(cx, enum_type);
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
- return do enum_name.to_c_str().with_ref |enum_name| {
+ return do enum_name.with_c_str |enum_name| {
unsafe {
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
let member_offset = machine::llelement_offset(cx, composite_llvm_type, i);
let member_name: &str = member_names[i];
- do member_name.to_c_str().with_ref |member_name| {
+ do member_name.with_c_str |member_name| {
unsafe {
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
})
.collect();
- return do composite_type_name.to_c_str().with_ref |name| {
+ return do composite_type_name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateStructType(
DIB(cx),
debug!("unimplemented_type_metadata: %?", ty::get(t));
let name = ty_to_str(cx.tcx, t);
- let metadata = do fmt!("NYI<%s>", name).to_c_str().with_ref |name| {
+ let metadata = do fmt!("NYI<%s>", name).with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateBasicType(
DIB(cx),
cx.dbg_cx.get_ref().builder
}
+fn assert_fcx_has_span(fcx: &FunctionContext) {
+ if fcx.span.is_none() {
+ fcx.ccx.sess.bug(fmt!("debuginfo: Encountered function %s with invalid source span. \
+ This function should have been ignored by debuginfo generation.",
+ ast_map::path_to_str(fcx.path, fcx.ccx.sess.intr())));
+ }
+}
// This procedure builds the *scope map* for a given function, which maps any given ast::NodeId in
// the function's AST to the correct DIScope metadata instance.
assert_eq!(datum.appropriate_mode(tcx), ByValue);
Store(bcx, datum.to_appropriate_llval(bcx), llfn);
let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
- Store(bcx, base::null_env_ptr(bcx), llenv);
+ Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
DatumBlock {bcx: bcx, datum: scratch}
}
debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
let dest = {
- if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
+ if ty::type_is_voidish(ty) {
Ignore
} else {
dest
ty::RvalueDpsExpr => {
let ty = expr_ty(bcx, expr);
- if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
+ if ty::type_is_voidish(ty) {
bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
return nil(bcx, ty);
} else {
let symbol = csearch::get_symbol(
bcx.ccx().sess.cstore,
did);
- let llval = do symbol.to_c_str().with_ref |buf| {
+ let llval = do symbol.with_c_str |buf| {
llvm::LLVMAddGlobal(bcx.ccx().llmod,
llty.to_ref(),
buf)
// except according to those terms.
-use back::{link, abi};
-use lib::llvm::{Pointer, ValueRef};
+use back::{link};
+use std::libc::c_uint;
+use lib::llvm::{ValueRef, Attribute, CallConv};
+use lib::llvm::llvm;
use lib;
-use middle::trans::base::*;
+use middle::trans::machine;
+use middle::trans::base;
+use middle::trans::base::push_ctxt;
use middle::trans::cabi;
-use middle::trans::cabi_x86;
-use middle::trans::cabi_x86_64;
-use middle::trans::cabi_arm;
-use middle::trans::cabi_mips;
use middle::trans::build::*;
-use middle::trans::callee::*;
+use middle::trans::builder::noname;
use middle::trans::common::*;
-use middle::trans::datum::*;
-use middle::trans::expr::Ignore;
-use middle::trans::machine::llsize_of;
-use middle::trans::glue;
-use middle::trans::machine;
use middle::trans::type_of::*;
use middle::trans::type_of;
use middle::ty;
use middle::ty::FnSig;
-use util::ppaux::ty_to_str;
-use std::cell::Cell;
+use std::uint;
use std::vec;
use syntax::codemap::span;
-use syntax::{ast, ast_util};
+use syntax::{ast};
use syntax::{attr, ast_map};
-use syntax::opt_vec;
use syntax::parse::token::special_idents;
-use syntax::parse::token;
-use syntax::abi::{X86, X86_64, Arm, Mips};
use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall,
- Cdecl, Aapcs, C};
+ Cdecl, Aapcs, C, AbiSet};
+use util::ppaux::{Repr, UserString};
use middle::trans::type_::Type;
-fn abi_info(ccx: @mut CrateContext) -> @cabi::ABIInfo {
- return match ccx.sess.targ_cfg.arch {
- X86 => cabi_x86::abi_info(ccx),
- X86_64 => cabi_x86_64::abi_info(),
- Arm => cabi_arm::abi_info(),
- Mips => cabi_mips::abi_info(),
- }
-}
-
-pub fn link_name(ccx: &CrateContext, i: &ast::foreign_item) -> @str {
- match attr::first_attr_value_str_by_name(i.attrs, "link_name") {
- None => ccx.sess.str_of(i.ident),
- Some(ln) => ln,
- }
-}
+///////////////////////////////////////////////////////////////////////////
+// Type definitions
-struct ShimTypes {
+struct ForeignTypes {
+ /// Rust signature of the function
fn_sig: ty::FnSig,
+ /// Adapter object for handling native ABI rules (trust me, you
+ /// don't want to know)
+ fn_ty: cabi::FnType,
+
/// LLVM types that will appear on the foreign function
llsig: LlvmSignature,
/// True if there is a return value (not bottom, not unit)
ret_def: bool,
-
- /// Type of the struct we will use to shuttle values back and forth.
- /// This is always derived from the llsig.
- bundle_ty: Type,
-
- /// Type of the shim function itself.
- shim_fn_ty: Type,
-
- /// Adapter object for handling native ABI rules (trust me, you
- /// don't want to know).
- fn_ty: cabi::FnType
}
struct LlvmSignature {
+ // LLVM versions of the types of this function's arguments.
llarg_tys: ~[Type],
- llret_ty: Type,
- sret: bool,
-}
-fn foreign_signature(ccx: &mut CrateContext, fn_sig: &ty::FnSig)
- -> LlvmSignature {
- /*!
- * The ForeignSignature is the LLVM types of the arguments/return type
- * of a function. Note that these LLVM types are not quite the same
- * as the LLVM types would be for a native Rust function because foreign
- * functions just plain ignore modes. They also don't pass aggregate
- * values by pointer like we do.
- */
+ // LLVM version of the type that this function returns. Note that
+ // this *may not be* the declared return type of the foreign
+ // function, because the foreign function may opt to return via an
+ // out pointer.
+ llret_ty: Type,
- let llarg_tys = fn_sig.inputs.map(|arg_ty| type_of(ccx, *arg_ty));
- let llret_ty = type_of::type_of(ccx, fn_sig.output);
- LlvmSignature {
- llarg_tys: llarg_tys,
- llret_ty: llret_ty,
- sret: !ty::type_is_immediate(ccx.tcx, fn_sig.output),
- }
+ // True if *Rust* would use an outpointer for this function.
+ sret: bool,
}
-fn shim_types(ccx: @mut CrateContext, id: ast::NodeId) -> ShimTypes {
- let fn_sig = match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty {
- ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
- _ => ccx.sess.bug("c_arg_and_ret_lltys called on non-function type")
- };
- let llsig = foreign_signature(ccx, &fn_sig);
- let bundle_ty = Type::struct_(llsig.llarg_tys + &[llsig.llret_ty.ptr_to()], false);
- let ret_def = !ty::type_is_bot(fn_sig.output) &&
- !ty::type_is_nil(fn_sig.output);
- let fn_ty = abi_info(ccx).compute_info(llsig.llarg_tys, llsig.llret_ty, ret_def);
- ShimTypes {
- fn_sig: fn_sig,
- llsig: llsig,
- ret_def: ret_def,
- bundle_ty: bundle_ty,
- shim_fn_ty: Type::func([bundle_ty.ptr_to()], &Type::void()),
- fn_ty: fn_ty
- }
-}
-type shim_arg_builder<'self> =
- &'self fn(bcx: @mut Block, tys: &ShimTypes,
- llargbundle: ValueRef) -> ~[ValueRef];
-
-type shim_ret_builder<'self> =
- &'self fn(bcx: @mut Block, tys: &ShimTypes,
- llargbundle: ValueRef,
- llretval: ValueRef);
-
-fn build_shim_fn_(ccx: @mut CrateContext,
- shim_name: &str,
- llbasefn: ValueRef,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv,
- arg_builder: shim_arg_builder,
- ret_builder: shim_ret_builder)
- -> ValueRef {
- let llshimfn = decl_internal_cdecl_fn(
- ccx.llmod, shim_name, tys.shim_fn_ty);
-
- // Declare the body of the shim function:
- let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
-
- let llargbundle = get_param(llshimfn, 0u);
- let llargvals = arg_builder(bcx, tys, llargbundle);
-
- // Create the call itself and store the return value:
- let llretval = CallWithConv(bcx, llbasefn, llargvals, cc);
-
- ret_builder(bcx, tys, llargbundle, llretval);
-
- // Don't finish up the function in the usual way, because this doesn't
- // follow the normal Rust calling conventions.
- let ret_cx = match fcx.llreturn {
- Some(llreturn) => raw_block(fcx, false, llreturn),
- None => bcx
- };
- RetVoid(ret_cx);
- fcx.cleanup();
+///////////////////////////////////////////////////////////////////////////
+// Calls to external functions
- return llshimfn;
-}
+fn llvm_calling_convention(ccx: @mut CrateContext,
+ abis: AbiSet)
+ -> Option<CallConv> {
+ let arch = ccx.sess.targ_cfg.arch;
+ abis.for_arch(arch).map(|abi| {
+ match *abi {
+ RustIntrinsic => {
+ // Intrinsics are emitted by monomorphic fn
+ ccx.sess.bug(fmt!("Asked to register intrinsic fn"));
+ }
-type wrap_arg_builder<'self> = &'self fn(bcx: @mut Block,
- tys: &ShimTypes,
- llwrapfn: ValueRef,
- llargbundle: ValueRef);
-
-type wrap_ret_builder<'self> = &'self fn(bcx: @mut Block,
- tys: &ShimTypes,
- llargbundle: ValueRef);
-
-fn build_wrap_fn_(ccx: @mut CrateContext,
- tys: &ShimTypes,
- llshimfn: ValueRef,
- llwrapfn: ValueRef,
- shim_upcall: ValueRef,
- needs_c_return: bool,
- arg_builder: wrap_arg_builder,
- ret_builder: wrap_ret_builder) {
- let _icx = push_ctxt("foreign::build_wrap_fn_");
- let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
-
- // Patch up the return type if it's not immediate and we're returning via
- // the C ABI.
- if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
- let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output);
- fcx.llretptr = Some(alloca(bcx, lloutputtype, ""));
- }
+ Rust => {
+ // FIXME(#3678) Implement linking to foreign fns with Rust ABI
+ ccx.sess.unimpl(
+ fmt!("Foreign functions with Rust ABI"));
+ }
- // Allocate the struct and write the arguments into it.
- let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle");
- arg_builder(bcx, tys, llwrapfn, llargbundle);
+ Stdcall => lib::llvm::X86StdcallCallConv,
+ Fastcall => lib::llvm::X86FastcallCallConv,
+ C => lib::llvm::CCallConv,
- // Create call itself.
- let llshimfnptr = PointerCast(bcx, llshimfn, Type::i8p());
- let llrawargbundle = PointerCast(bcx, llargbundle, Type::i8p());
- Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]);
- ret_builder(bcx, tys, llargbundle);
+ // NOTE These API constants ought to be more specific
+ Cdecl => lib::llvm::CCallConv,
+ Aapcs => lib::llvm::CCallConv,
+ }
+ })
+}
- // Then return according to the C ABI.
- let return_context = match fcx.llreturn {
- Some(llreturn) => raw_block(fcx, false, llreturn),
- None => bcx
- };
- let llfunctiontype = val_ty(llwrapfn);
- let llfunctiontype = llfunctiontype.element_type();
- let return_type = llfunctiontype.return_type();
- if return_type.kind() == ::lib::llvm::Void {
- // XXX: This might be wrong if there are any functions for which
- // the C ABI specifies a void output pointer and the Rust ABI
- // does not.
- RetVoid(return_context);
- } else {
- // Cast if we have to...
- // XXX: This is ugly.
- let llretptr = BitCast(return_context, fcx.llretptr.unwrap(), return_type.ptr_to());
- Ret(return_context, Load(return_context, llretptr));
- }
- fcx.cleanup();
-}
+pub fn register_foreign_item_fn(ccx: @mut CrateContext,
+ abis: AbiSet,
+ path: &ast_map::path,
+ foreign_item: @ast::foreign_item) -> ValueRef {
+ /*!
+ * Registers a foreign function found in a library.
+ * Just adds a LLVM global.
+ */
-// For each foreign function F, we generate a wrapper function W and a shim
-// function S that all work together. The wrapper function W is the function
-// that other rust code actually invokes. Its job is to marshall the
-// arguments into a struct. It then uses a small bit of assembly to switch
-// over to the C stack and invoke the shim function. The shim function S then
-// unpacks the arguments from the struct and invokes the actual function F
-// according to its specified calling convention.
-//
-// Example: Given a foreign c-stack function F(x: X, y: Y) -> Z,
-// we generate a wrapper function W that looks like:
-//
-// void W(Z* dest, void *env, X x, Y y) {
-// struct { X x; Y y; Z *z; } args = { x, y, z };
-// call_on_c_stack_shim(S, &args);
-// }
-//
-// The shim function S then looks something like:
-//
-// void S(struct { X x; Y y; Z *z; } *args) {
-// *args->z = F(args->x, args->y);
-// }
-//
-// However, if the return type of F is dynamically sized or of aggregate type,
-// the shim function looks like:
-//
-// void S(struct { X x; Y y; Z *z; } *args) {
-// F(args->z, args->x, args->y);
-// }
-//
-// Note: on i386, the layout of the args struct is generally the same
-// as the desired layout of the arguments on the C stack. Therefore,
-// we could use upcall_alloc_c_stack() to allocate the `args`
-// structure and switch the stack pointer appropriately to avoid a
-// round of copies. (In fact, the shim function itself is
-// unnecessary). We used to do this, in fact, and will perhaps do so
-// in the future.
-pub fn trans_foreign_mod(ccx: @mut CrateContext,
- path: &ast_map::path,
- foreign_mod: &ast::foreign_mod) {
- let _icx = push_ctxt("foreign::trans_foreign_mod");
+ debug!("register_foreign_item_fn(abis=%s, \
+ path=%s, \
+ foreign_item.id=%?)",
+ abis.repr(ccx.tcx),
+ path.repr(ccx.tcx),
+ foreign_item.id);
- let arch = ccx.sess.targ_cfg.arch;
- let abi = match foreign_mod.abis.for_arch(arch) {
+ let cc = match llvm_calling_convention(ccx, abis) {
+ Some(cc) => cc,
None => {
+ // FIXME(#8357) We really ought to report a span here
ccx.sess.fatal(
- fmt!("No suitable ABI for target architecture \
+ fmt!("ABI `%s` has no suitable ABI \
+ for target architecture \
in module %s",
+ abis.user_string(ccx.tcx),
ast_map::path_to_str(*path,
ccx.sess.intr())));
}
-
- Some(abi) => abi,
};
- for &foreign_item in foreign_mod.items.iter() {
- match foreign_item.node {
- ast::foreign_item_fn(*) => {
- let id = foreign_item.id;
- match abi {
- RustIntrinsic => {
- // Intrinsics are emitted by monomorphic fn
- }
-
- Rust => {
- // FIXME(#3678) Implement linking to foreign fns with Rust ABI
- ccx.sess.unimpl(
- fmt!("Foreign functions with Rust ABI"));
- }
-
- Stdcall => {
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::X86StdcallCallConv);
- }
-
- Fastcall => {
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::X86FastcallCallConv);
- }
-
- Cdecl => {
- // FIXME(#3678) should really be more specific
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::CCallConv);
- }
-
- Aapcs => {
- // FIXME(#3678) should really be more specific
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::CCallConv);
- }
-
- C => {
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::CCallConv);
- }
- }
- }
- ast::foreign_item_static(*) => {
- let ident = token::ident_to_str(&foreign_item.ident);
- ccx.item_symbols.insert(foreign_item.id, /* bad */ident.to_owned());
- }
- }
- }
+ // Register the function as a C extern fn
+ let lname = link_name(ccx, foreign_item);
+ let tys = foreign_types_for_id(ccx, foreign_item.id);
- fn build_foreign_fn(ccx: @mut CrateContext,
- id: ast::NodeId,
- foreign_item: @ast::foreign_item,
- cc: lib::llvm::CallConv) {
- let llwrapfn = get_item_val(ccx, id);
- let tys = shim_types(ccx, id);
- if attr::contains_name(foreign_item.attrs, "rust_stack") {
- build_direct_fn(ccx, llwrapfn, foreign_item,
- &tys, cc);
- } else if attr::contains_name(foreign_item.attrs, "fast_ffi") {
- build_fast_ffi_fn(ccx, llwrapfn, foreign_item, &tys, cc);
- } else {
- let llshimfn = build_shim_fn(ccx, foreign_item, &tys, cc);
- build_wrap_fn(ccx, &tys, llshimfn, llwrapfn);
- }
- }
+ // Create the LLVM value for the C extern fn
+ let llfn_ty = lltype_for_fn_from_foreign_types(&tys);
+ let llfn = base::get_extern_fn(&mut ccx.externs, ccx.llmod,
+ lname, cc, llfn_ty);
+ add_argument_attributes(&tys, llfn);
- fn build_shim_fn(ccx: @mut CrateContext,
- foreign_item: &ast::foreign_item,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv)
- -> ValueRef {
- /*!
- *
- * Build S, from comment above:
- *
- * void S(struct { X x; Y y; Z *z; } *args) {
- * F(args->z, args->x, args->y);
- * }
- */
-
- let _icx = push_ctxt("foreign::build_shim_fn");
-
- fn build_args(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef)
- -> ~[ValueRef] {
- let _icx = push_ctxt("foreign::shim::build_args");
- tys.fn_ty.build_shim_args(bcx, tys.llsig.llarg_tys, llargbundle)
- }
+ return llfn;
+}
- fn build_ret(bcx: @mut Block,
- tys: &ShimTypes,
- llargbundle: ValueRef,
- llretval: ValueRef) {
- let _icx = push_ctxt("foreign::shim::build_ret");
- tys.fn_ty.build_shim_ret(bcx,
- tys.llsig.llarg_tys,
- tys.ret_def,
- llargbundle,
- llretval);
- }
+pub fn trans_native_call(bcx: @mut Block,
+ callee_ty: ty::t,
+ llfn: ValueRef,
+ llretptr: ValueRef,
+ llargs_rust: &[ValueRef]) -> @mut Block {
+ /*!
+ * Prepares a call to a native function. This requires adapting
+ * from the Rust argument passing rules to the native rules.
+ *
+ * # Parameters
+ *
+ * - `callee_ty`: Rust type for the function we are calling
+ * - `llfn`: the function pointer we are calling
+ * - `llretptr`: where to store the return value of the function
+ * - `llargs_rust`: a list of the argument values, prepared
+ * as they would be if calling a Rust function
+ */
- let lname = link_name(ccx, foreign_item);
- let llbasefn = base_fn(ccx, lname, tys, cc);
- // Name the shim function
- let shim_name = fmt!("%s__c_stack_shim", lname);
- build_shim_fn_(ccx,
- shim_name,
- llbasefn,
- tys,
- cc,
- build_args,
- build_ret)
- }
+ let ccx = bcx.ccx();
+ let tcx = bcx.tcx();
- fn base_fn(ccx: &CrateContext,
- lname: &str,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv)
- -> ValueRef {
- // Declare the "prototype" for the base function F:
- do tys.fn_ty.decl_fn |fnty| {
- decl_fn(ccx.llmod, lname, cc, fnty)
- }
- }
+ debug!("trans_native_call(callee_ty=%s, \
+ llfn=%s, \
+ llretptr=%s)",
+ callee_ty.repr(tcx),
+ ccx.tn.val_to_str(llfn),
+ ccx.tn.val_to_str(llretptr));
- // FIXME (#2535): this is very shaky and probably gets ABIs wrong all
- // over the place
- fn build_direct_fn(ccx: @mut CrateContext,
- decl: ValueRef,
- item: &ast::foreign_item,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv) {
- debug!("build_direct_fn(%s)", link_name(ccx, item));
-
- let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
- let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
- let ty = ty::lookup_item_type(ccx.tcx,
- ast_util::local_def(item.id)).ty;
- let ret_ty = ty::ty_fn_ret(ty);
- let args = vec::from_fn(ty::ty_fn_args(ty).len(), |i| {
- get_param(decl, fcx.arg_pos(i))
- });
- let retval = Call(bcx, llbasefn, args);
- if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
- Store(bcx, retval, fcx.llretptr.unwrap());
+ let (fn_abis, fn_sig) = match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref fn_ty) => (fn_ty.abis, fn_ty.sig.clone()),
+ _ => ccx.sess.bug("trans_native_call called on non-function type")
+ };
+ let llsig = foreign_signature(ccx, &fn_sig);
+ let ret_def = !ty::type_is_voidish(fn_sig.output);
+ let fn_type = cabi::compute_abi_info(ccx,
+ llsig.llarg_tys,
+ llsig.llret_ty,
+ ret_def);
+
+ let all_arg_tys: &[cabi::LLVMType] = fn_type.arg_tys;
+ let all_attributes: &[Option<Attribute>] = fn_type.attrs;
+
+ let mut llargs_foreign = ~[];
+
+ // If the foreign ABI expects return value by pointer, supply the
+ // pointer that Rust gave us. Sometimes we have to bitcast
+ // because foreign fns return slightly different (but equivalent)
+ // views on the same type (e.g., i64 in place of {i32,i32}).
+ let (arg_tys, attributes) = {
+ if fn_type.sret {
+ if all_arg_tys[0].cast {
+ let llcastedretptr =
+ BitCast(bcx, llretptr, all_arg_tys[0].ty.ptr_to());
+ llargs_foreign.push(llcastedretptr);
+ } else {
+ llargs_foreign.push(llretptr);
+ }
+ (all_arg_tys.tail(), all_attributes.tail())
+ } else {
+ (all_arg_tys, all_attributes)
}
- finish_fn(fcx, bcx);
- }
+ };
- // FIXME (#2535): this is very shaky and probably gets ABIs wrong all
- // over the place
- fn build_fast_ffi_fn(ccx: @mut CrateContext,
- decl: ValueRef,
- item: &ast::foreign_item,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv) {
- debug!("build_fast_ffi_fn(%s)", link_name(ccx, item));
-
- let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
- let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
- set_no_inline(fcx.llfn);
- set_fixed_stack_segment(fcx.llfn);
- let ty = ty::lookup_item_type(ccx.tcx,
- ast_util::local_def(item.id)).ty;
- let ret_ty = ty::ty_fn_ret(ty);
- let args = vec::from_fn(ty::ty_fn_args(ty).len(), |i| {
- get_param(decl, fcx.arg_pos(i))
- });
- let retval = Call(bcx, llbasefn, args);
- if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
- Store(bcx, retval, fcx.llretptr.unwrap());
- }
- finish_fn(fcx, bcx);
- }
+ for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
+ let mut llarg_rust = llarg_rust;
- fn build_wrap_fn(ccx: @mut CrateContext,
- tys: &ShimTypes,
- llshimfn: ValueRef,
- llwrapfn: ValueRef) {
- /*!
- *
- * Build W, from comment above:
- *
- * void W(Z* dest, void *env, X x, Y y) {
- * struct { X x; Y y; Z *z; } args = { x, y, z };
- * call_on_c_stack_shim(S, &args);
- * }
- *
- * One thing we have to be very careful of is to
- * account for the Rust modes.
- */
-
- let _icx = push_ctxt("foreign::build_wrap_fn");
-
- build_wrap_fn_(ccx,
- tys,
- llshimfn,
- llwrapfn,
- ccx.upcalls.call_shim_on_c_stack,
- false,
- build_args,
- build_ret);
-
- fn build_args(bcx: @mut Block,
- tys: &ShimTypes,
- llwrapfn: ValueRef,
- llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::wrap::build_args");
- let ccx = bcx.ccx();
- let n = tys.llsig.llarg_tys.len();
- for i in range(0u, n) {
- let arg_i = bcx.fcx.arg_pos(i);
- let mut llargval = get_param(llwrapfn, arg_i);
-
- // In some cases, Rust will pass a pointer which the
- // native C type doesn't have. In that case, just
- // load the value from the pointer.
- if type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) {
- llargval = Load(bcx, llargval);
- }
+ // Does Rust pass this argument by pointer?
+ let rust_indirect = type_of::arg_is_indirect(ccx, fn_sig.inputs[i]);
- store_inbounds(bcx, llargval, llargbundle, [0u, i]);
- }
+ debug!("argument %u, llarg_rust=%s, rust_indirect=%b, arg_ty=%s",
+ i,
+ ccx.tn.val_to_str(llarg_rust),
+ rust_indirect,
+ ccx.tn.type_to_str(arg_tys[i].ty));
- for &retptr in bcx.fcx.llretptr.iter() {
- store_inbounds(bcx, retptr, llargbundle, [0u, n]);
- }
+ // Ensure that we always have the Rust value indirectly,
+ // because it makes bitcasting easier.
+ if !rust_indirect {
+ let scratch = base::alloca(bcx, arg_tys[i].ty, "__arg");
+ Store(bcx, llarg_rust, scratch);
+ llarg_rust = scratch;
}
- fn build_ret(bcx: @mut Block,
- shim_types: &ShimTypes,
- llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::wrap::build_ret");
- let arg_count = shim_types.fn_sig.inputs.len();
- for &retptr in bcx.fcx.llretptr.iter() {
- let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]);
- Store(bcx, Load(bcx, llretptr), retptr);
- }
- }
- }
-}
+ debug!("llarg_rust=%s (after indirection)",
+ ccx.tn.val_to_str(llarg_rust));
-pub fn trans_intrinsic(ccx: @mut CrateContext,
- decl: ValueRef,
- item: &ast::foreign_item,
- path: ast_map::path,
- substs: @param_substs,
- attributes: &[ast::Attribute],
- ref_id: Option<ast::NodeId>) {
- debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
-
- fn simple_llvm_intrinsic(bcx: @mut Block, name: &'static str, num_args: uint) {
- assert!(num_args <= 4);
- let mut args = [0 as ValueRef, ..4];
- let first_real_arg = bcx.fcx.arg_pos(0u);
- for i in range(0u, num_args) {
- args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
+ // Check whether we need to do any casting
+ let foreignarg_ty = arg_tys[i].ty;
+ if arg_tys[i].cast {
+ llarg_rust = BitCast(bcx, llarg_rust, foreignarg_ty.ptr_to());
}
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
- }
-
- fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
- let first_real_arg = bcx.fcx.arg_pos(0u);
- let a = get_param(bcx.fcx.llfn, first_real_arg);
- let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
-
- // convert `i1` to a `bool`, and write to the out parameter
- let val = Call(bcx, llfn, [a, b]);
- let result = ExtractValue(bcx, val, 0);
- let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
- let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
- let ret = Load(bcx, retptr);
- let ret = InsertValue(bcx, ret, result, 0);
- let ret = InsertValue(bcx, ret, overflow, 1);
- Store(bcx, ret, retptr);
- RetVoid(bcx)
- }
- fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
- let ccx = bcx.ccx();
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
- let size = match sizebits {
- 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
- 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
- _ => ccx.sess.fatal("Invalid value for sizebits")
- };
+ debug!("llarg_rust=%s (after casting)",
+ ccx.tn.val_to_str(llarg_rust));
- let decl = bcx.fcx.llfn;
- let first_real_arg = bcx.fcx.arg_pos(0u);
- let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
- let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
- let count = get_param(decl, first_real_arg + 2);
- let volatile = C_i1(false);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
- RetVoid(bcx);
- }
-
- fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
- let ccx = bcx.ccx();
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
- let size = match sizebits {
- 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
- 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
- _ => ccx.sess.fatal("Invalid value for sizebits")
+ // Finally, load the value if needed for the foreign ABI
+ let foreign_indirect = attributes[i].is_some();
+ let llarg_foreign = if foreign_indirect {
+ llarg_rust
+ } else {
+ Load(bcx, llarg_rust)
};
- let decl = bcx.fcx.llfn;
- let first_real_arg = bcx.fcx.arg_pos(0u);
- let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
- let val = get_param(decl, first_real_arg + 1);
- let count = get_param(decl, first_real_arg + 2);
- let volatile = C_i1(false);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
- RetVoid(bcx);
- }
+ debug!("argument %u, llarg_foreign=%s",
+ i, ccx.tn.val_to_str(llarg_foreign));
- fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
- let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
- let y = C_i1(false);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Ret(bcx, Call(bcx, llfn, [x, y]));
+ llargs_foreign.push(llarg_foreign);
}
- let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
-
- let fcx = new_fn_ctxt_w_id(ccx,
- path,
- decl,
- item.id,
- output_type,
- true,
- Some(substs),
- None,
- Some(item.span));
-
- set_always_inline(fcx.llfn);
+ let cc = match llvm_calling_convention(ccx, fn_abis) {
+ Some(cc) => cc,
+ None => {
+ // FIXME(#8357) We really ought to report a span here
+ ccx.sess.fatal(
+ fmt!("ABI string `%s` has no suitable ABI \
+ for target architecture",
+ fn_abis.user_string(ccx.tcx)));
+ }
+ };
- // Set the fixed stack segment flag if necessary.
- if attr::contains_name(attributes, "fixed_stack_segment") {
- set_fixed_stack_segment(fcx.llfn);
- }
+ let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc);
- let mut bcx = fcx.entry_bcx.unwrap();
- let first_real_arg = fcx.arg_pos(0u);
+ // If the function we just called does not use an outpointer,
+ // store the result into the rust outpointer. Cast the outpointer
+ // type to match because some ABIs will use a different type than
+ // the Rust type. e.g., a {u32,u32} struct could be returned as
+ // u64.
+ if ret_def && !fn_type.sret {
+ let llrust_ret_ty = llsig.llret_ty;
+ let llforeign_ret_ty = fn_type.ret_ty.ty;
- let nm = ccx.sess.str_of(item.ident);
- let name = nm.as_slice();
+ debug!("llretptr=%s", ccx.tn.val_to_str(llretptr));
+ debug!("llforeign_retval=%s", ccx.tn.val_to_str(llforeign_retval));
+ debug!("llrust_ret_ty=%s", ccx.tn.type_to_str(llrust_ret_ty));
+ debug!("llforeign_ret_ty=%s", ccx.tn.type_to_str(llforeign_ret_ty));
- // This requires that atomic intrinsics follow a specific naming pattern:
- // "atomic_<operation>[_<ordering>], and no ordering means SeqCst
- if name.starts_with("atomic_") {
- let split : ~[&str] = name.split_iter('_').collect();
- assert!(split.len() >= 2, "Atomic intrinsic not correct format");
- let order = if split.len() == 2 {
- lib::llvm::SequentiallyConsistent
+ if llrust_ret_ty == llforeign_ret_ty {
+ Store(bcx, llforeign_retval, llretptr);
} else {
- match split[2] {
- "relaxed" => lib::llvm::Monotonic,
- "acq" => lib::llvm::Acquire,
- "rel" => lib::llvm::Release,
- "acqrel" => lib::llvm::AcquireRelease,
- _ => ccx.sess.fatal("Unknown ordering in atomic intrinsic")
- }
- };
-
- match split[1] {
- "cxchg" => {
- let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg),
- get_param(decl, first_real_arg + 1u),
- get_param(decl, first_real_arg + 2u),
- order);
- Ret(bcx, old);
- }
- "load" => {
- let old = AtomicLoad(bcx, get_param(decl, first_real_arg),
- order);
- Ret(bcx, old);
- }
- "store" => {
- AtomicStore(bcx, get_param(decl, first_real_arg + 1u),
- get_param(decl, first_real_arg),
- order);
- RetVoid(bcx);
- }
- "fence" => {
- AtomicFence(bcx, order);
- RetVoid(bcx);
- }
- op => {
- // These are all AtomicRMW ops
- let atom_op = match op {
- "xchg" => lib::llvm::Xchg,
- "xadd" => lib::llvm::Add,
- "xsub" => lib::llvm::Sub,
- "and" => lib::llvm::And,
- "nand" => lib::llvm::Nand,
- "or" => lib::llvm::Or,
- "xor" => lib::llvm::Xor,
- "max" => lib::llvm::Max,
- "min" => lib::llvm::Min,
- "umax" => lib::llvm::UMax,
- "umin" => lib::llvm::UMin,
- _ => ccx.sess.fatal("Unknown atomic operation")
- };
-
- let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg),
- get_param(decl, first_real_arg + 1u),
- order);
- Ret(bcx, old);
- }
+ // The actual return type is a struct, but the ABI
+ // adaptation code has cast it into some scalar type. The
+ // code that follows is the only reliable way I have
+ // found to do a transform like i64 -> {i32,i32}.
+ // Basically we dump the data onto the stack then memcpy it.
+ //
+ // Other approaches I tried:
+ // - Casting rust ret pointer to the foreign type and using Store
+ // is (a) unsafe if size of foreign type > size of rust type and
+ // (b) runs afoul of strict aliasing rules, yielding invalid
+ // assembly under -O (specifically, the store gets removed).
+ // - Truncating foreign type to correct integral type and then
+ // bitcasting to the struct type yields invalid cast errors.
+ let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
+ Store(bcx, llforeign_retval, llscratch);
+ let llscratch_i8 = BitCast(bcx, llscratch, Type::i8().ptr_to());
+ let llretptr_i8 = BitCast(bcx, llretptr, Type::i8().ptr_to());
+ let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
+ let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
+ let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
+ let llalign = uint::min(llforeign_align, llrust_align);
+ debug!("llrust_size=%?", llrust_size);
+ base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
+ C_uint(ccx, llrust_size), llalign as u32);
}
-
- fcx.cleanup();
- return;
}
- match name {
- "size_of" => {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)));
- }
- "move_val" => {
- // Create a datum reflecting the value being moved.
- // Use `appropriate_mode` so that the datum is by ref
- // if the value is non-immediate. Note that, with
- // intrinsics, there are no argument cleanups to
- // concern ourselves with.
- let tp_ty = substs.tys[0];
- let mode = appropriate_mode(ccx.tcx, tp_ty);
- let src = Datum {val: get_param(decl, first_real_arg + 1u),
- ty: tp_ty, mode: mode};
- bcx = src.move_to(bcx, DROP_EXISTING,
- get_param(decl, first_real_arg));
- RetVoid(bcx);
- }
- "move_val_init" => {
- // See comments for `"move_val"`.
- let tp_ty = substs.tys[0];
- let mode = appropriate_mode(ccx.tcx, tp_ty);
- let src = Datum {val: get_param(decl, first_real_arg + 1u),
- ty: tp_ty, mode: mode};
- bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
- RetVoid(bcx);
- }
- "min_align_of" => {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)));
- }
- "pref_align_of"=> {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)));
- }
- "get_tydesc" => {
- let tp_ty = substs.tys[0];
- let static_ti = get_tydesc(ccx, tp_ty);
- glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
-
- // FIXME (#3730): ideally this shouldn't need a cast,
- // but there's a circularity between translating rust types to llvm
- // types and having a tydesc type available. So I can't directly access
- // the llvm type of intrinsic::TyDesc struct.
- let userland_tydesc_ty = type_of::type_of(ccx, output_type);
- let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty);
- Ret(bcx, td);
- }
- "init" => {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- match bcx.fcx.llretptr {
- Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
- None if ty::type_is_nil(tp_ty) => RetVoid(bcx),
- None => Ret(bcx, C_null(lltp_ty)),
- }
- }
- "uninit" => {
- // Do nothing, this is effectively a no-op
- let retty = substs.tys[0];
- if ty::type_is_immediate(ccx.tcx, retty) && !ty::type_is_nil(retty) {
- unsafe {
- Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
- }
- } else {
- RetVoid(bcx)
- }
- }
- "forget" => {
- RetVoid(bcx);
- }
- "transmute" => {
- let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
- let llintype = type_of::type_of(ccx, in_type);
- let llouttype = type_of::type_of(ccx, out_type);
-
- let in_type_size = machine::llbitsize_of_real(ccx, llintype);
- let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
- if in_type_size != out_type_size {
- let sp = match ccx.tcx.items.get_copy(&ref_id.unwrap()) {
- ast_map::node_expr(e) => e.span,
- _ => fail!("transmute has non-expr arg"),
- };
- let pluralize = |n| if 1u == n { "" } else { "s" };
- ccx.sess.span_fatal(sp,
- fmt!("transmute called on types with \
- different sizes: %s (%u bit%s) to \
- %s (%u bit%s)",
- ty_to_str(ccx.tcx, in_type),
- in_type_size,
- pluralize(in_type_size),
- ty_to_str(ccx.tcx, out_type),
- out_type_size,
- pluralize(out_type_size)));
- }
+ return bcx;
+}
- if !ty::type_is_nil(out_type) {
- let llsrcval = get_param(decl, first_real_arg);
- if ty::type_is_immediate(ccx.tcx, in_type) {
- match fcx.llretptr {
- Some(llretptr) => {
- Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
- RetVoid(bcx);
- }
- None => match (llintype.kind(), llouttype.kind()) {
- (Pointer, other) | (other, Pointer) if other != Pointer => {
- let tmp = Alloca(bcx, llouttype, "");
- Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
- Ret(bcx, Load(bcx, tmp));
- }
- _ => Ret(bcx, BitCast(bcx, llsrcval, llouttype))
- }
- }
- } else if ty::type_is_immediate(ccx.tcx, out_type) {
- let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
- Ret(bcx, Load(bcx, llsrcptr));
- } else {
- // NB: Do not use a Load and Store here. This causes massive
- // code bloat when `transmute` is used on large structural
- // types.
- let lldestptr = fcx.llretptr.unwrap();
- let lldestptr = PointerCast(bcx, lldestptr, Type::i8p());
- let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p());
-
- let llsize = llsize_of(ccx, llintype);
- call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
- RetVoid(bcx);
- };
- } else {
- RetVoid(bcx);
- }
- }
- "needs_drop" => {
- let tp_ty = substs.tys[0];
- Ret(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)));
- }
- "contains_managed" => {
- let tp_ty = substs.tys[0];
- Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()));
- }
- "visit_tydesc" => {
- let td = get_param(decl, first_real_arg);
- let visitor = get_param(decl, first_real_arg + 1u);
- let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
- glue::call_tydesc_glue_full(bcx, visitor, td,
- abi::tydesc_field_visit_glue, None);
- RetVoid(bcx);
- }
- "frame_address" => {
- let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
- let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)]);
- let star_u8 = ty::mk_imm_ptr(
- bcx.tcx(),
- ty::mk_mach_uint(ast::ty_u8));
- let fty = ty::mk_closure(bcx.tcx(), ty::ClosureTy {
- purity: ast::impure_fn,
- sigil: ast::BorrowedSigil,
- onceness: ast::Many,
- region: ty::re_bound(ty::br_anon(0)),
- bounds: ty::EmptyBuiltinBounds(),
- sig: FnSig {
- bound_lifetime_names: opt_vec::Empty,
- inputs: ~[ star_u8 ],
- output: ty::mk_nil()
- }
- });
- let datum = Datum {val: get_param(decl, first_real_arg),
- mode: ByRef(ZeroMem), ty: fty};
- let arg_vals = ~[frameaddress_val];
- bcx = trans_call_inner(
- bcx, None, fty, ty::mk_nil(),
- |bcx| Callee {bcx: bcx, data: Closure(datum)},
- ArgVals(arg_vals), Some(Ignore), DontAutorefArg).bcx;
- RetVoid(bcx);
- }
- "morestack_addr" => {
- // XXX This is a hack to grab the address of this particular
- // native function. There should be a general in-language
- // way to do this
- let llfty = type_of_fn(bcx.ccx(), [], ty::mk_nil());
- let morestack_addr = decl_cdecl_fn(
- bcx.ccx().llmod, "__morestack", llfty);
- let morestack_addr = PointerCast(bcx, morestack_addr, Type::nil().ptr_to());
- Ret(bcx, morestack_addr);
- }
- "offset" => {
- let ptr = get_param(decl, first_real_arg);
- let offset = get_param(decl, first_real_arg + 1);
- Ret(bcx, GEP(bcx, ptr, [offset]));
- }
- "offset_inbounds" => {
- let ptr = get_param(decl, first_real_arg);
- let offset = get_param(decl, first_real_arg + 1);
- Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
- }
- "memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
- "memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
- "memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
- "memmove64" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i64", substs.tys[0], 64),
- "memset32" => memset_intrinsic(bcx, "llvm.memset.p0i8.i32", substs.tys[0], 32),
- "memset64" => memset_intrinsic(bcx, "llvm.memset.p0i8.i64", substs.tys[0], 64),
- "sqrtf32" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f32", 1),
- "sqrtf64" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f64", 1),
- "powif32" => simple_llvm_intrinsic(bcx, "llvm.powi.f32", 2),
- "powif64" => simple_llvm_intrinsic(bcx, "llvm.powi.f64", 2),
- "sinf32" => simple_llvm_intrinsic(bcx, "llvm.sin.f32", 1),
- "sinf64" => simple_llvm_intrinsic(bcx, "llvm.sin.f64", 1),
- "cosf32" => simple_llvm_intrinsic(bcx, "llvm.cos.f32", 1),
- "cosf64" => simple_llvm_intrinsic(bcx, "llvm.cos.f64", 1),
- "powf32" => simple_llvm_intrinsic(bcx, "llvm.pow.f32", 2),
- "powf64" => simple_llvm_intrinsic(bcx, "llvm.pow.f64", 2),
- "expf32" => simple_llvm_intrinsic(bcx, "llvm.exp.f32", 1),
- "expf64" => simple_llvm_intrinsic(bcx, "llvm.exp.f64", 1),
- "exp2f32" => simple_llvm_intrinsic(bcx, "llvm.exp2.f32", 1),
- "exp2f64" => simple_llvm_intrinsic(bcx, "llvm.exp2.f64", 1),
- "logf32" => simple_llvm_intrinsic(bcx, "llvm.log.f32", 1),
- "logf64" => simple_llvm_intrinsic(bcx, "llvm.log.f64", 1),
- "log10f32" => simple_llvm_intrinsic(bcx, "llvm.log10.f32", 1),
- "log10f64" => simple_llvm_intrinsic(bcx, "llvm.log10.f64", 1),
- "log2f32" => simple_llvm_intrinsic(bcx, "llvm.log2.f32", 1),
- "log2f64" => simple_llvm_intrinsic(bcx, "llvm.log2.f64", 1),
- "fmaf32" => simple_llvm_intrinsic(bcx, "llvm.fma.f32", 3),
- "fmaf64" => simple_llvm_intrinsic(bcx, "llvm.fma.f64", 3),
- "fabsf32" => simple_llvm_intrinsic(bcx, "llvm.fabs.f32", 1),
- "fabsf64" => simple_llvm_intrinsic(bcx, "llvm.fabs.f64", 1),
- "floorf32" => simple_llvm_intrinsic(bcx, "llvm.floor.f32", 1),
- "floorf64" => simple_llvm_intrinsic(bcx, "llvm.floor.f64", 1),
- "ceilf32" => simple_llvm_intrinsic(bcx, "llvm.ceil.f32", 1),
- "ceilf64" => simple_llvm_intrinsic(bcx, "llvm.ceil.f64", 1),
- "truncf32" => simple_llvm_intrinsic(bcx, "llvm.trunc.f32", 1),
- "truncf64" => simple_llvm_intrinsic(bcx, "llvm.trunc.f64", 1),
- "ctpop8" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i8", 1),
- "ctpop16" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i16", 1),
- "ctpop32" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i32", 1),
- "ctpop64" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i64", 1),
- "ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
- "ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),
- "ctlz32" => count_zeros_intrinsic(bcx, "llvm.ctlz.i32"),
- "ctlz64" => count_zeros_intrinsic(bcx, "llvm.ctlz.i64"),
- "cttz8" => count_zeros_intrinsic(bcx, "llvm.cttz.i8"),
- "cttz16" => count_zeros_intrinsic(bcx, "llvm.cttz.i16"),
- "cttz32" => count_zeros_intrinsic(bcx, "llvm.cttz.i32"),
- "cttz64" => count_zeros_intrinsic(bcx, "llvm.cttz.i64"),
- "bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
- "bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
- "bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
-
- "i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
- "i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
- "i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
- "i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
-
- "u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
- "u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
- "u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
- "u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
-
- "i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
- "i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
- "i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
- "i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
-
- "u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
- "u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
- "u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
- "u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
-
- "i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
- "i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
- "i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
- "i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
-
- "u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
- "u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
- "u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
- "u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
-
- _ => {
- // Could we make this an enum rather than a string? does it get
- // checked earlier?
- ccx.sess.span_bug(item.span, "unknown intrinsic");
- }
+pub fn trans_foreign_mod(ccx: @mut CrateContext,
+ foreign_mod: &ast::foreign_mod) {
+ let _icx = push_ctxt("foreign::trans_foreign_mod");
+ for &foreign_item in foreign_mod.items.iter() {
+ let lname = link_name(ccx, foreign_item);
+ ccx.item_symbols.insert(foreign_item.id, lname.to_owned());
}
- fcx.cleanup();
}
-/**
- * Translates a "crust" fn, meaning a Rust fn that can be called
- * from C code. In this case, we have to perform some adaptation
- * to (1) switch back to the Rust stack and (2) adapt the C calling
- * convention to our own.
- *
- * Example: Given a crust fn F(x: X, y: Y) -> Z, we generate a
- * Rust function R as normal:
- *
- * void R(Z* dest, void *env, X x, Y y) {...}
- *
- * and then we generate a wrapper function W that looks like:
- *
- * Z W(X x, Y y) {
- * struct { X x; Y y; Z *z; } args = { x, y, z };
- * call_on_c_stack_shim(S, &args);
- * }
- *
- * Note that the wrapper follows the foreign (typically "C") ABI.
- * The wrapper is the actual "value" of the foreign fn. Finally,
- * we generate a shim function S that looks like:
- *
- * void S(struct { X x; Y y; Z *z; } *args) {
- * R(args->z, NULL, args->x, args->y);
- * }
- */
-pub fn trans_foreign_fn(ccx: @mut CrateContext,
- path: ast_map::path,
- decl: &ast::fn_decl,
- body: &ast::Block,
- llwrapfn: ValueRef,
- id: ast::NodeId) {
+///////////////////////////////////////////////////////////////////////////
+// Rust functions with foreign ABIs
+//
+// These are normal Rust functions defined with foreign ABIs. For
+// now, and perhaps forever, we translate these using a "layer of
+// indirection". That is, given a Rust declaration like:
+//
+// extern "C" fn foo(i: u32) -> u32 { ... }
+//
+// we will generate a function like:
+//
+// S foo(T i) {
+// S r;
+// foo0(&r, NULL, i);
+// return r;
+// }
+//
+// #[inline_always]
+// void foo0(uint32_t *r, void *env, uint32_t i) { ... }
+//
+// Here the (internal) `foo0` function follows the Rust ABI as normal,
+// where the `foo` function follows the C ABI. We rely on LLVM to
+// inline the one into the other. Of course we could just generate the
+// correct code in the first place, but this is much simpler.
+
+pub fn register_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
+ sp: span,
+ sym: ~str,
+ node_id: ast::NodeId)
+ -> ValueRef {
+ let _icx = push_ctxt("foreign::register_foreign_fn");
+
+ let tys = foreign_types_for_id(ccx, node_id);
+ let llfn_ty = lltype_for_fn_from_foreign_types(&tys);
+ let llfn = base::register_fn_llvmty(ccx,
+ sp,
+ sym,
+ node_id,
+ lib::llvm::CCallConv,
+ llfn_ty);
+ add_argument_attributes(&tys, llfn);
+ debug!("register_rust_fn_with_foreign_abi(node_id=%?, llfn_ty=%s, llfn=%s)",
+ node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn));
+ llfn
+}
+
+pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
+ path: &ast_map::path,
+ decl: &ast::fn_decl,
+ body: &ast::Block,
+ llwrapfn: ValueRef,
+ id: ast::NodeId) {
let _icx = push_ctxt("foreign::build_foreign_fn");
+ let tys = foreign_types_for_id(ccx, id);
+
+ unsafe { // unsafe because we call LLVM operations
+ // Build up the Rust function (`foo0` above).
+ let llrustfn = build_rust_fn(ccx, path, decl, body, id);
+
+ // Build up the foreign wrapper (`foo` above).
+ return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
+ }
fn build_rust_fn(ccx: @mut CrateContext,
path: &ast_map::path,
decl: &ast::fn_decl,
body: &ast::Block,
id: ast::NodeId)
- -> ValueRef {
+ -> ValueRef {
let _icx = push_ctxt("foreign::foreign::build_rust_fn");
- let t = ty::node_id_to_type(ccx.tcx, id);
- // XXX: Bad copy.
+ let tcx = ccx.tcx;
+ let t = ty::node_id_to_type(tcx, id);
let ps = link::mangle_internal_name_by_path(
- ccx,
- vec::append_one((*path).clone(),
- ast_map::path_name(
- special_idents::clownshoe_abi)));
+ ccx, vec::append_one((*path).clone(), ast_map::path_name(
+ special_idents::clownshoe_abi
+ )));
let llty = type_of_fn_from_ty(ccx, t);
- let llfndecl = decl_internal_cdecl_fn(ccx.llmod, ps, llty);
- trans_fn(ccx,
- (*path).clone(),
- decl,
- body,
- llfndecl,
- no_self,
- None,
- id,
- []);
+ let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
+ base::trans_fn(ccx,
+ (*path).clone(),
+ decl,
+ body,
+ llfndecl,
+ base::no_self,
+ None,
+ id,
+ []);
return llfndecl;
}
- fn build_shim_fn(ccx: @mut CrateContext,
- path: ast_map::path,
- llrustfn: ValueRef,
- tys: &ShimTypes)
- -> ValueRef {
- /*!
- *
- * Generate the shim S:
- *
- * void S(struct { X x; Y y; Z *z; } *args) {
- * R(args->z, NULL, &args->x, args->y);
- * }
- *
- * One complication is that we must adapt to the Rust
- * calling convention, which introduces indirection
- * in some cases. To demonstrate this, I wrote one of the
- * entries above as `&args->x`, because presumably `X` is
- * one of those types that is passed by pointer in Rust.
- */
-
- let _icx = push_ctxt("foreign::foreign::build_shim_fn");
-
- fn build_args(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef)
- -> ~[ValueRef] {
- let _icx = push_ctxt("foreign::extern::shim::build_args");
- let ccx = bcx.ccx();
- let mut llargvals = ~[];
- let mut i = 0u;
- let n = tys.fn_sig.inputs.len();
-
- if !ty::type_is_immediate(bcx.tcx(), tys.fn_sig.output) {
- let llretptr = load_inbounds(bcx, llargbundle, [0u, n]);
- llargvals.push(llretptr);
+ unsafe fn build_wrap_fn(ccx: @mut CrateContext,
+ llrustfn: ValueRef,
+ llwrapfn: ValueRef,
+ tys: &ForeignTypes) {
+ let _icx = push_ctxt(
+ "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
+ let tcx = ccx.tcx;
+
+ debug!("build_wrap_fn(llrustfn=%s, llwrapfn=%s)",
+ ccx.tn.val_to_str(llrustfn),
+ ccx.tn.val_to_str(llwrapfn));
+
+ // Avoid all the Rust generation stuff and just generate raw
+ // LLVM here.
+ //
+ // We want to generate code like this:
+ //
+ // S foo(T i) {
+ // S r;
+ // foo0(&r, NULL, i);
+ // return r;
+ // }
+
+ let the_block =
+ "the block".to_c_str().with_ref(
+ |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llwrapfn, s));
+
+ let builder = ccx.builder.B;
+ llvm::LLVMPositionBuilderAtEnd(builder, the_block);
+
+ // Array for the arguments we will pass to the rust function.
+ let mut llrust_args = ~[];
+ let mut next_foreign_arg_counter: c_uint = 0;
+ let next_foreign_arg: &fn() -> c_uint = {
+ || {
+ next_foreign_arg_counter += 1;
+ next_foreign_arg_counter - 1
}
+ };
- let llenvptr = C_null(Type::opaque_box(bcx.ccx()).ptr_to());
- llargvals.push(llenvptr);
- while i < n {
- // Get a pointer to the argument:
- let mut llargval = GEPi(bcx, llargbundle, [0u, i]);
+ // If there is an out pointer on the foreign function
+ let foreign_outptr = {
+ if tys.fn_ty.sret {
+ Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg()))
+ } else {
+ None
+ }
+ };
- if !type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) {
- // If Rust would pass this by value, load the value.
- llargval = Load(bcx, llargval);
+ // Push Rust return pointer, using null if it will be unused.
+ let rust_uses_outptr =
+ type_of::return_uses_outptr(tcx, tys.fn_sig.output);
+ let return_alloca: Option<ValueRef>;
+ let llrust_ret_ty = tys.llsig.llret_ty;
+ let llrust_retptr_ty = llrust_ret_ty.ptr_to();
+ if rust_uses_outptr {
+ // Rust expects to use an outpointer. If the foreign fn
+ // also uses an outpointer, we can reuse it, but the types
+ // may vary, so cast first to the Rust type. If the
+ // foriegn fn does NOT use an outpointer, we will have to
+ // alloca some scratch space on the stack.
+ match foreign_outptr {
+ Some(llforeign_outptr) => {
+ debug!("out pointer, foreign=%s",
+ ccx.tn.val_to_str(llforeign_outptr));
+ let llrust_retptr =
+ llvm::LLVMBuildBitCast(builder,
+ llforeign_outptr,
+ llrust_ret_ty.ptr_to().to_ref(),
+ noname());
+ debug!("out pointer, foreign=%s (casted)",
+ ccx.tn.val_to_str(llrust_retptr));
+ llrust_args.push(llrust_retptr);
+ return_alloca = None;
}
- llargvals.push(llargval);
- i += 1u;
+ None => {
+ let slot = {
+ "return_alloca".to_c_str().with_ref(
+ |s| llvm::LLVMBuildAlloca(builder,
+ llrust_ret_ty.to_ref(),
+ s))
+ };
+ debug!("out pointer, \
+ allocad=%s, \
+ llrust_ret_ty=%s, \
+ return_ty=%s",
+ ccx.tn.val_to_str(slot),
+ ccx.tn.type_to_str(llrust_ret_ty),
+ tys.fn_sig.output.repr(tcx));
+ llrust_args.push(slot);
+ return_alloca = Some(slot);
+ }
+ }
+ } else {
+ // Rust does not expect an outpointer. If the foreign fn
+ // does use an outpointer, then we will do a store of the
+ // value that the Rust fn returns.
+ return_alloca = None;
+ };
+
+ // Push an (null) env pointer
+ let env_pointer = base::null_env_ptr(ccx);
+ debug!("env pointer=%s", ccx.tn.val_to_str(env_pointer));
+ llrust_args.push(env_pointer);
+
+ // Build up the arguments to the call to the rust function.
+ // Careful to adapt for cases where the native convention uses
+ // a pointer and Rust does not or vice versa.
+ for i in range(0, tys.fn_sig.inputs.len()) {
+ let rust_ty = tys.fn_sig.inputs[i];
+ let llrust_ty = tys.llsig.llarg_tys[i];
+ let foreign_index = next_foreign_arg();
+ let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
+ let foreign_indirect = tys.fn_ty.attrs[foreign_index].is_some();
+ let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index);
+
+ debug!("llforeign_arg #%u: %s",
+ i, ccx.tn.val_to_str(llforeign_arg));
+ debug!("rust_indirect = %b, foreign_indirect = %b",
+ rust_indirect, foreign_indirect);
+
+ // Ensure that the foreign argument is indirect (by
+ // pointer). It makes adapting types easier, since we can
+ // always just bitcast pointers.
+ if !foreign_indirect {
+ let lltemp =
+ llvm::LLVMBuildAlloca(
+ builder, val_ty(llforeign_arg).to_ref(), noname());
+ llvm::LLVMBuildStore(
+ builder, llforeign_arg, lltemp);
+ llforeign_arg = lltemp;
+ }
+
+ // If the types in the ABI and the Rust types don't match,
+ // bitcast the llforeign_arg pointer so it matches the types
+ // Rust expects.
+ if tys.fn_ty.arg_tys[foreign_index].cast {
+ assert!(!foreign_indirect);
+ llforeign_arg = llvm::LLVMBuildBitCast(
+ builder, llforeign_arg,
+ llrust_ty.ptr_to().to_ref(), noname());
}
- return llargvals;
- }
- fn build_ret(bcx: @mut Block,
- shim_types: &ShimTypes,
- llargbundle: ValueRef,
- llretval: ValueRef) {
- if bcx.fcx.llretptr.is_some() &&
- ty::type_is_immediate(bcx.tcx(), shim_types.fn_sig.output) {
- // Write the value into the argument bundle.
- let arg_count = shim_types.fn_sig.inputs.len();
- let llretptr = load_inbounds(bcx,
- llargbundle,
- [0, arg_count]);
- Store(bcx, llretval, llretptr);
+ let llrust_arg = if rust_indirect {
+ llforeign_arg
} else {
- // NB: The return pointer in the Rust ABI function is wired
- // directly into the return slot in the shim struct.
+ llvm::LLVMBuildLoad(builder, llforeign_arg, noname())
+ };
+
+ debug!("llrust_arg #%u: %s",
+ i, ccx.tn.val_to_str(llrust_arg));
+ llrust_args.push(llrust_arg);
+ }
+
+ // Perform the call itself
+ let llrust_ret_val = do llrust_args.as_imm_buf |ptr, len| {
+ debug!("calling llrustfn = %s", ccx.tn.val_to_str(llrustfn));
+ llvm::LLVMBuildCall(builder, llrustfn, ptr,
+ len as c_uint, noname())
+ };
+
+ // Get the return value where the foreign fn expects it.
+ let llforeign_ret_ty = tys.fn_ty.ret_ty.ty;
+ match foreign_outptr {
+ None if !tys.ret_def => {
+ // Function returns `()` or `bot`, which in Rust is the LLVM
+ // type "{}" but in foreign ABIs is "Void".
+ llvm::LLVMBuildRetVoid(builder);
+ }
+
+ None if rust_uses_outptr => {
+ // Rust uses an outpointer, but the foreign ABI does not. Load.
+ let llrust_outptr = return_alloca.unwrap();
+ let llforeign_outptr_casted =
+ llvm::LLVMBuildBitCast(builder,
+ llrust_outptr,
+ llforeign_ret_ty.ptr_to().to_ref(),
+ noname());
+ let llforeign_retval =
+ llvm::LLVMBuildLoad(builder, llforeign_outptr_casted, noname());
+ llvm::LLVMBuildRet(builder, llforeign_retval);
+ }
+
+ None if llforeign_ret_ty != llrust_ret_ty => {
+ // Neither ABI uses an outpointer, but the types don't
+ // quite match. Must cast. Probably we should try and
+ // examine the types and use a concrete llvm cast, but
+ // right now we just use a temp memory location and
+ // bitcast the pointer, which is the same thing the
+ // old wrappers used to do.
+ let lltemp =
+ llvm::LLVMBuildAlloca(
+ builder, llforeign_ret_ty.to_ref(), noname());
+ let lltemp_casted =
+ llvm::LLVMBuildBitCast(builder,
+ lltemp,
+ llrust_ret_ty.ptr_to().to_ref(),
+ noname());
+ llvm::LLVMBuildStore(
+ builder, llrust_ret_val, lltemp_casted);
+ let llforeign_retval =
+ llvm::LLVMBuildLoad(builder, lltemp, noname());
+ llvm::LLVMBuildRet(builder, llforeign_retval);
+ }
+
+ None => {
+ // Neither ABI uses an outpointer, and the types
+ // match. Easy peasy.
+ llvm::LLVMBuildRet(builder, llrust_ret_val);
+ }
+
+ Some(llforeign_outptr) if !rust_uses_outptr => {
+ // Foreign ABI requires an out pointer, but Rust doesn't.
+ // Store Rust return value.
+ let llforeign_outptr_casted =
+ llvm::LLVMBuildBitCast(builder,
+ llforeign_outptr,
+ llrust_retptr_ty.to_ref(),
+ noname());
+ llvm::LLVMBuildStore(
+ builder, llrust_ret_val, llforeign_outptr_casted);
+ llvm::LLVMBuildRetVoid(builder);
+ }
+
+ Some(_) => {
+ // Both ABIs use outpointers. Easy peasy.
+ llvm::LLVMBuildRetVoid(builder);
}
}
+ }
+}
- let shim_name = link::mangle_internal_name_by_path(
- ccx,
- vec::append_one(path, ast_map::path_name(
- special_idents::clownshoe_stack_shim
- )));
- build_shim_fn_(ccx,
- shim_name,
- llrustfn,
- tys,
- lib::llvm::CCallConv,
- build_args,
- build_ret)
+///////////////////////////////////////////////////////////////////////////
+// General ABI Support
+//
+// This code is kind of a confused mess and needs to be reworked given
+// the massive simplifications that have occurred.
+
+pub fn link_name(ccx: &CrateContext, i: @ast::foreign_item) -> @str {
+ match attr::first_attr_value_str_by_name(i.attrs, "link_name") {
+ None => ccx.sess.str_of(i.ident),
+ Some(ln) => ln,
}
+}
- fn build_wrap_fn(ccx: @mut CrateContext,
- llshimfn: ValueRef,
- llwrapfn: ValueRef,
- tys: &ShimTypes) {
- /*!
- *
- * Generate the wrapper W:
- *
- * Z W(X x, Y y) {
- * struct { X x; Y y; Z *z; } args = { x, y, z };
- * call_on_c_stack_shim(S, &args);
- * }
- */
-
- let _icx = push_ctxt("foreign::foreign::build_wrap_fn");
-
- build_wrap_fn_(ccx,
- tys,
- llshimfn,
- llwrapfn,
- ccx.upcalls.call_shim_on_rust_stack,
- true,
- build_args,
- build_ret);
-
- fn build_args(bcx: @mut Block,
- tys: &ShimTypes,
- llwrapfn: ValueRef,
- llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::foreign::wrap::build_args");
- tys.fn_ty.build_wrap_args(bcx,
- tys.llsig.llret_ty,
- llwrapfn,
- llargbundle);
- }
+fn foreign_signature(ccx: &mut CrateContext, fn_sig: &ty::FnSig)
+ -> LlvmSignature {
+ /*!
+ * The ForeignSignature is the LLVM types of the arguments/return type
+ * of a function. Note that these LLVM types are not quite the same
+ * as the LLVM types would be for a native Rust function because foreign
+ * functions just plain ignore modes. They also don't pass aggregate
+ * values by pointer like we do.
+ */
- fn build_ret(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::foreign::wrap::build_ret");
- tys.fn_ty.build_wrap_ret(bcx, tys.llsig.llarg_tys, llargbundle);
- }
+ let llarg_tys = fn_sig.inputs.map(|&arg| type_of(ccx, arg));
+ let llret_ty = type_of::type_of(ccx, fn_sig.output);
+ LlvmSignature {
+ llarg_tys: llarg_tys,
+ llret_ty: llret_ty,
+ sret: type_of::return_uses_outptr(ccx.tcx, fn_sig.output),
}
+}
- let tys = shim_types(ccx, id);
- // The internal Rust ABI function - runs on the Rust stack
- // XXX: Bad copy.
- let llrustfn = build_rust_fn(ccx, &path, decl, body, id);
- // The internal shim function - runs on the Rust stack
- let llshimfn = build_shim_fn(ccx, path, llrustfn, &tys);
- // The foreign C function - runs on the C stack
- build_wrap_fn(ccx, llshimfn, llwrapfn, &tys)
+fn foreign_types_for_id(ccx: &mut CrateContext,
+ id: ast::NodeId) -> ForeignTypes {
+ foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx, id))
}
-pub fn register_foreign_fn(ccx: @mut CrateContext,
- sp: span,
- sym: ~str,
- node_id: ast::NodeId)
- -> ValueRef {
- let _icx = push_ctxt("foreign::register_foreign_fn");
+fn foreign_types_for_fn_ty(ccx: &mut CrateContext,
+ ty: ty::t) -> ForeignTypes {
+ let fn_sig = match ty::get(ty).sty {
+ ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
+ _ => ccx.sess.bug("foreign_types_for_fn_ty called on non-function type")
+ };
+ let llsig = foreign_signature(ccx, &fn_sig);
+ let ret_def = !ty::type_is_voidish(fn_sig.output);
+ let fn_ty = cabi::compute_abi_info(ccx,
+ llsig.llarg_tys,
+ llsig.llret_ty,
+ ret_def);
+ debug!("foreign_types_for_fn_ty(\
+ ty=%s, \
+ llsig=%s -> %s, \
+ fn_ty=%s -> %s, \
+ ret_def=%b",
+ ty.repr(ccx.tcx),
+ ccx.tn.types_to_str(llsig.llarg_tys),
+ ccx.tn.type_to_str(llsig.llret_ty),
+ ccx.tn.types_to_str(fn_ty.arg_tys.map(|t| t.ty)),
+ ccx.tn.type_to_str(fn_ty.ret_ty.ty),
+ ret_def);
+
+ ForeignTypes {
+ fn_sig: fn_sig,
+ llsig: llsig,
+ ret_def: ret_def,
+ fn_ty: fn_ty
+ }
+}
- let sym = Cell::new(sym);
+fn lltype_for_fn_from_foreign_types(tys: &ForeignTypes) -> Type {
+ let llargument_tys: ~[Type] =
+ tys.fn_ty.arg_tys.iter().map(|t| t.ty).collect();
+ let llreturn_ty = tys.fn_ty.ret_ty.ty;
+ Type::func(llargument_tys, &llreturn_ty)
+}
+
+pub fn lltype_for_foreign_fn(ccx: &mut CrateContext, ty: ty::t) -> Type {
+ let fn_types = foreign_types_for_fn_ty(ccx, ty);
+ lltype_for_fn_from_foreign_types(&fn_types)
+}
- let tys = shim_types(ccx, node_id);
- do tys.fn_ty.decl_fn |fnty| {
- register_fn_llvmty(ccx, sp, sym.take(), node_id, lib::llvm::CCallConv, fnty)
+fn add_argument_attributes(tys: &ForeignTypes,
+ llfn: ValueRef) {
+ for (i, a) in tys.fn_ty.attrs.iter().enumerate() {
+ match *a {
+ Some(attr) => {
+ let llarg = get_param(llfn, i);
+ unsafe {
+ llvm::LLVMAddAttribute(llarg, attr as c_uint);
+ }
+ }
+ None => ()
+ }
}
}
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc").to_managed();
note_unique_llvm_symbol(ccx, name);
debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), name);
- let gvar = do name.to_c_str().with_ref |buf| {
+ let gvar = do name.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type.to_ref(), buf)
}
--- /dev/null
+// Copyright 2012-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.
+
+use back::{abi};
+use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
+use lib::llvm::{ValueRef, Pointer};
+use lib;
+use middle::trans::base::*;
+use middle::trans::build::*;
+use middle::trans::callee::*;
+use middle::trans::common::*;
+use middle::trans::datum::*;
+use middle::trans::type_of::*;
+use middle::trans::type_of;
+use middle::trans::expr::Ignore;
+use middle::trans::machine;
+use middle::trans::glue;
+use middle::ty::FnSig;
+use middle::ty;
+use syntax::ast;
+use syntax::ast_map;
+use syntax::attr;
+use syntax::opt_vec;
+use util::ppaux::{ty_to_str};
+use middle::trans::machine::llsize_of;
+use middle::trans::type_::Type;
+
+pub fn trans_intrinsic(ccx: @mut CrateContext,
+ decl: ValueRef,
+ item: &ast::foreign_item,
+ path: ast_map::path,
+ substs: @param_substs,
+ attributes: &[ast::Attribute],
+ ref_id: Option<ast::NodeId>) {
+ debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
+
+ fn simple_llvm_intrinsic(bcx: @mut Block, name: &'static str, num_args: uint) {
+ assert!(num_args <= 4);
+ let mut args = [0 as ValueRef, ..4];
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ for i in range(0u, num_args) {
+ args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
+ }
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
+ }
+
+ fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ let a = get_param(bcx.fcx.llfn, first_real_arg);
+ let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+
+ // convert `i1` to a `bool`, and write to the out parameter
+ let val = Call(bcx, llfn, [a, b]);
+ let result = ExtractValue(bcx, val, 0);
+ let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
+ let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
+ let ret = Load(bcx, retptr);
+ let ret = InsertValue(bcx, ret, result, 0);
+ let ret = InsertValue(bcx, ret, overflow, 1);
+ Store(bcx, ret, retptr);
+ RetVoid(bcx)
+ }
+
+ fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+ let ccx = bcx.ccx();
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
+ let size = match sizebits {
+ 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
+ 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
+ _ => ccx.sess.fatal("Invalid value for sizebits")
+ };
+
+ let decl = bcx.fcx.llfn;
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
+ let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
+ let count = get_param(decl, first_real_arg + 2);
+ let volatile = C_i1(false);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
+ RetVoid(bcx);
+ }
+
+ fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+ let ccx = bcx.ccx();
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
+ let size = match sizebits {
+ 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
+ 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
+ _ => ccx.sess.fatal("Invalid value for sizebits")
+ };
+
+ let decl = bcx.fcx.llfn;
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
+ let val = get_param(decl, first_real_arg + 1);
+ let count = get_param(decl, first_real_arg + 2);
+ let volatile = C_i1(false);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
+ RetVoid(bcx);
+ }
+
+ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
+ let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
+ let y = C_i1(false);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Ret(bcx, Call(bcx, llfn, [x, y]));
+ }
+
+ let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
+
+ let fcx = new_fn_ctxt_w_id(ccx,
+ path,
+ decl,
+ item.id,
+ output_type,
+ true,
+ Some(substs),
+ None,
+ Some(item.span));
+
+ set_always_inline(fcx.llfn);
+
+ // Set the fixed stack segment flag if necessary.
+ if attr::contains_name(attributes, "fixed_stack_segment") {
+ set_fixed_stack_segment(fcx.llfn);
+ }
+
+ let mut bcx = fcx.entry_bcx.unwrap();
+ let first_real_arg = fcx.arg_pos(0u);
+
+ let nm = ccx.sess.str_of(item.ident);
+ let name = nm.as_slice();
+
+ // This requires that atomic intrinsics follow a specific naming pattern:
+ // "atomic_<operation>[_<ordering>], and no ordering means SeqCst
+ if name.starts_with("atomic_") {
+ let split : ~[&str] = name.split_iter('_').collect();
+ assert!(split.len() >= 2, "Atomic intrinsic not correct format");
+ let order = if split.len() == 2 {
+ lib::llvm::SequentiallyConsistent
+ } else {
+ match split[2] {
+ "relaxed" => lib::llvm::Monotonic,
+ "acq" => lib::llvm::Acquire,
+ "rel" => lib::llvm::Release,
+ "acqrel" => lib::llvm::AcquireRelease,
+ _ => ccx.sess.fatal("Unknown ordering in atomic intrinsic")
+ }
+ };
+
+ match split[1] {
+ "cxchg" => {
+ let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg),
+ get_param(decl, first_real_arg + 1u),
+ get_param(decl, first_real_arg + 2u),
+ order);
+ Ret(bcx, old);
+ }
+ "load" => {
+ let old = AtomicLoad(bcx, get_param(decl, first_real_arg),
+ order);
+ Ret(bcx, old);
+ }
+ "store" => {
+ AtomicStore(bcx, get_param(decl, first_real_arg + 1u),
+ get_param(decl, first_real_arg),
+ order);
+ RetVoid(bcx);
+ }
+ "fence" => {
+ AtomicFence(bcx, order);
+ RetVoid(bcx);
+ }
+ op => {
+ // These are all AtomicRMW ops
+ let atom_op = match op {
+ "xchg" => lib::llvm::Xchg,
+ "xadd" => lib::llvm::Add,
+ "xsub" => lib::llvm::Sub,
+ "and" => lib::llvm::And,
+ "nand" => lib::llvm::Nand,
+ "or" => lib::llvm::Or,
+ "xor" => lib::llvm::Xor,
+ "max" => lib::llvm::Max,
+ "min" => lib::llvm::Min,
+ "umax" => lib::llvm::UMax,
+ "umin" => lib::llvm::UMin,
+ _ => ccx.sess.fatal("Unknown atomic operation")
+ };
+
+ let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg),
+ get_param(decl, first_real_arg + 1u),
+ order);
+ Ret(bcx, old);
+ }
+ }
+
+ fcx.cleanup();
+ return;
+ }
+
+ match name {
+ "size_of" => {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)));
+ }
+ "move_val" => {
+ // Create a datum reflecting the value being moved.
+ // Use `appropriate_mode` so that the datum is by ref
+ // if the value is non-immediate. Note that, with
+ // intrinsics, there are no argument cleanups to
+ // concern ourselves with.
+ let tp_ty = substs.tys[0];
+ let mode = appropriate_mode(ccx.tcx, tp_ty);
+ let src = Datum {val: get_param(decl, first_real_arg + 1u),
+ ty: tp_ty, mode: mode};
+ bcx = src.move_to(bcx, DROP_EXISTING,
+ get_param(decl, first_real_arg));
+ RetVoid(bcx);
+ }
+ "move_val_init" => {
+ // See comments for `"move_val"`.
+ let tp_ty = substs.tys[0];
+ let mode = appropriate_mode(ccx.tcx, tp_ty);
+ let src = Datum {val: get_param(decl, first_real_arg + 1u),
+ ty: tp_ty, mode: mode};
+ bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
+ RetVoid(bcx);
+ }
+ "min_align_of" => {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)));
+ }
+ "pref_align_of"=> {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)));
+ }
+ "get_tydesc" => {
+ let tp_ty = substs.tys[0];
+ let static_ti = get_tydesc(ccx, tp_ty);
+ glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
+
+ // FIXME (#3730): ideally this shouldn't need a cast,
+ // but there's a circularity between translating rust types to llvm
+ // types and having a tydesc type available. So I can't directly access
+ // the llvm type of intrinsic::TyDesc struct.
+ let userland_tydesc_ty = type_of::type_of(ccx, output_type);
+ let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty);
+ Ret(bcx, td);
+ }
+ "init" => {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ match bcx.fcx.llretptr {
+ Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
+ None if ty::type_is_nil(tp_ty) => RetVoid(bcx),
+ None => Ret(bcx, C_null(lltp_ty)),
+ }
+ }
+ "uninit" => {
+ // Do nothing, this is effectively a no-op
+ let retty = substs.tys[0];
+ if ty::type_is_immediate(ccx.tcx, retty) && !ty::type_is_nil(retty) {
+ unsafe {
+ Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
+ }
+ } else {
+ RetVoid(bcx)
+ }
+ }
+ "forget" => {
+ RetVoid(bcx);
+ }
+ "transmute" => {
+ let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
+ let llintype = type_of::type_of(ccx, in_type);
+ let llouttype = type_of::type_of(ccx, out_type);
+
+ let in_type_size = machine::llbitsize_of_real(ccx, llintype);
+ let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
+ if in_type_size != out_type_size {
+ let sp = match ccx.tcx.items.get_copy(&ref_id.unwrap()) {
+ ast_map::node_expr(e) => e.span,
+ _ => fail!("transmute has non-expr arg"),
+ };
+ let pluralize = |n| if 1u == n { "" } else { "s" };
+ ccx.sess.span_fatal(sp,
+ fmt!("transmute called on types with \
+ different sizes: %s (%u bit%s) to \
+ %s (%u bit%s)",
+ ty_to_str(ccx.tcx, in_type),
+ in_type_size,
+ pluralize(in_type_size),
+ ty_to_str(ccx.tcx, out_type),
+ out_type_size,
+ pluralize(out_type_size)));
+ }
+
+ if !ty::type_is_voidish(out_type) {
+ let llsrcval = get_param(decl, first_real_arg);
+ if ty::type_is_immediate(ccx.tcx, in_type) {
+ match fcx.llretptr {
+ Some(llretptr) => {
+ Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
+ RetVoid(bcx);
+ }
+ None => match (llintype.kind(), llouttype.kind()) {
+ (Pointer, other) | (other, Pointer) if other != Pointer => {
+ let tmp = Alloca(bcx, llouttype, "");
+ Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
+ Ret(bcx, Load(bcx, tmp));
+ }
+ _ => Ret(bcx, BitCast(bcx, llsrcval, llouttype))
+ }
+ }
+ } else if ty::type_is_immediate(ccx.tcx, out_type) {
+ let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
+ Ret(bcx, Load(bcx, llsrcptr));
+ } else {
+ // NB: Do not use a Load and Store here. This causes massive
+ // code bloat when `transmute` is used on large structural
+ // types.
+ let lldestptr = fcx.llretptr.unwrap();
+ let lldestptr = PointerCast(bcx, lldestptr, Type::i8p());
+ let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p());
+
+ let llsize = llsize_of(ccx, llintype);
+ call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
+ RetVoid(bcx);
+ };
+ } else {
+ RetVoid(bcx);
+ }
+ }
+ "needs_drop" => {
+ let tp_ty = substs.tys[0];
+ Ret(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)));
+ }
+ "contains_managed" => {
+ let tp_ty = substs.tys[0];
+ Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()));
+ }
+ "visit_tydesc" => {
+ let td = get_param(decl, first_real_arg);
+ let visitor = get_param(decl, first_real_arg + 1u);
+ let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
+ glue::call_tydesc_glue_full(bcx, visitor, td,
+ abi::tydesc_field_visit_glue, None);
+ RetVoid(bcx);
+ }
+ "frame_address" => {
+ let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
+ let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)]);
+ let star_u8 = ty::mk_imm_ptr(
+ bcx.tcx(),
+ ty::mk_mach_uint(ast::ty_u8));
+ let fty = ty::mk_closure(bcx.tcx(), ty::ClosureTy {
+ purity: ast::impure_fn,
+ sigil: ast::BorrowedSigil,
+ onceness: ast::Many,
+ region: ty::re_bound(ty::br_anon(0)),
+ bounds: ty::EmptyBuiltinBounds(),
+ sig: FnSig {
+ bound_lifetime_names: opt_vec::Empty,
+ inputs: ~[ star_u8 ],
+ output: ty::mk_nil()
+ }
+ });
+ let datum = Datum {val: get_param(decl, first_real_arg),
+ mode: ByRef(ZeroMem), ty: fty};
+ let arg_vals = ~[frameaddress_val];
+ bcx = trans_call_inner(
+ bcx, None, fty, ty::mk_nil(),
+ |bcx| Callee {bcx: bcx, data: Closure(datum)},
+ ArgVals(arg_vals), Some(Ignore), DontAutorefArg).bcx;
+ RetVoid(bcx);
+ }
+ "morestack_addr" => {
+ // XXX This is a hack to grab the address of this particular
+ // native function. There should be a general in-language
+ // way to do this
+ let llfty = type_of_rust_fn(bcx.ccx(), [], ty::mk_nil());
+ let morestack_addr = decl_cdecl_fn(
+ bcx.ccx().llmod, "__morestack", llfty);
+ let morestack_addr = PointerCast(bcx, morestack_addr, Type::nil().ptr_to());
+ Ret(bcx, morestack_addr);
+ }
+ "offset" => {
+ let ptr = get_param(decl, first_real_arg);
+ let offset = get_param(decl, first_real_arg + 1);
+ Ret(bcx, GEP(bcx, ptr, [offset]));
+ }
+ "offset_inbounds" => {
+ let ptr = get_param(decl, first_real_arg);
+ let offset = get_param(decl, first_real_arg + 1);
+ Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
+ }
+ "memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
+ "memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
+ "memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
+ "memmove64" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i64", substs.tys[0], 64),
+ "memset32" => memset_intrinsic(bcx, "llvm.memset.p0i8.i32", substs.tys[0], 32),
+ "memset64" => memset_intrinsic(bcx, "llvm.memset.p0i8.i64", substs.tys[0], 64),
+ "sqrtf32" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f32", 1),
+ "sqrtf64" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f64", 1),
+ "powif32" => simple_llvm_intrinsic(bcx, "llvm.powi.f32", 2),
+ "powif64" => simple_llvm_intrinsic(bcx, "llvm.powi.f64", 2),
+ "sinf32" => simple_llvm_intrinsic(bcx, "llvm.sin.f32", 1),
+ "sinf64" => simple_llvm_intrinsic(bcx, "llvm.sin.f64", 1),
+ "cosf32" => simple_llvm_intrinsic(bcx, "llvm.cos.f32", 1),
+ "cosf64" => simple_llvm_intrinsic(bcx, "llvm.cos.f64", 1),
+ "powf32" => simple_llvm_intrinsic(bcx, "llvm.pow.f32", 2),
+ "powf64" => simple_llvm_intrinsic(bcx, "llvm.pow.f64", 2),
+ "expf32" => simple_llvm_intrinsic(bcx, "llvm.exp.f32", 1),
+ "expf64" => simple_llvm_intrinsic(bcx, "llvm.exp.f64", 1),
+ "exp2f32" => simple_llvm_intrinsic(bcx, "llvm.exp2.f32", 1),
+ "exp2f64" => simple_llvm_intrinsic(bcx, "llvm.exp2.f64", 1),
+ "logf32" => simple_llvm_intrinsic(bcx, "llvm.log.f32", 1),
+ "logf64" => simple_llvm_intrinsic(bcx, "llvm.log.f64", 1),
+ "log10f32" => simple_llvm_intrinsic(bcx, "llvm.log10.f32", 1),
+ "log10f64" => simple_llvm_intrinsic(bcx, "llvm.log10.f64", 1),
+ "log2f32" => simple_llvm_intrinsic(bcx, "llvm.log2.f32", 1),
+ "log2f64" => simple_llvm_intrinsic(bcx, "llvm.log2.f64", 1),
+ "fmaf32" => simple_llvm_intrinsic(bcx, "llvm.fma.f32", 3),
+ "fmaf64" => simple_llvm_intrinsic(bcx, "llvm.fma.f64", 3),
+ "fabsf32" => simple_llvm_intrinsic(bcx, "llvm.fabs.f32", 1),
+ "fabsf64" => simple_llvm_intrinsic(bcx, "llvm.fabs.f64", 1),
+ "floorf32" => simple_llvm_intrinsic(bcx, "llvm.floor.f32", 1),
+ "floorf64" => simple_llvm_intrinsic(bcx, "llvm.floor.f64", 1),
+ "ceilf32" => simple_llvm_intrinsic(bcx, "llvm.ceil.f32", 1),
+ "ceilf64" => simple_llvm_intrinsic(bcx, "llvm.ceil.f64", 1),
+ "truncf32" => simple_llvm_intrinsic(bcx, "llvm.trunc.f32", 1),
+ "truncf64" => simple_llvm_intrinsic(bcx, "llvm.trunc.f64", 1),
+ "ctpop8" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i8", 1),
+ "ctpop16" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i16", 1),
+ "ctpop32" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i32", 1),
+ "ctpop64" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i64", 1),
+ "ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
+ "ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),
+ "ctlz32" => count_zeros_intrinsic(bcx, "llvm.ctlz.i32"),
+ "ctlz64" => count_zeros_intrinsic(bcx, "llvm.ctlz.i64"),
+ "cttz8" => count_zeros_intrinsic(bcx, "llvm.cttz.i8"),
+ "cttz16" => count_zeros_intrinsic(bcx, "llvm.cttz.i16"),
+ "cttz32" => count_zeros_intrinsic(bcx, "llvm.cttz.i32"),
+ "cttz64" => count_zeros_intrinsic(bcx, "llvm.cttz.i64"),
+ "bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
+ "bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
+ "bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
+
+ "i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
+ "i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
+ "i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
+ "i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
+
+ "u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
+ "u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
+ "u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
+ "u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
+
+ "i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
+ "i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
+ "i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
+ "i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
+
+ "u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
+ "u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
+ "u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
+ "u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
+
+ "i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
+ "i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
+ "i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
+ "i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
+
+ "u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
+ "u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
+ "u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
+ "u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
+
+ _ => {
+ // Could we make this an enum rather than a string? does it get
+ // checked earlier?
+ ccx.sess.span_bug(item.span, "unknown intrinsic");
+ }
+ }
+ fcx.cleanup();
+}
let tbl = C_struct(components);
let vtable = ccx.sess.str_of(gensym_name("vtable"));
- let vt_gvar = do vtable.to_c_str().with_ref |buf| {
+ let vt_gvar = do vtable.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl).to_ref(), buf)
};
llvm::LLVMSetInitializer(vt_gvar, tbl);
pub mod cabi_arm;
pub mod cabi_mips;
pub mod foreign;
+pub mod intrinsic;
pub mod reflect;
pub mod debuginfo;
pub mod type_use;
use middle::trans::base;
use middle::trans::common::*;
use middle::trans::datum;
-use middle::trans::foreign;
use middle::trans::machine;
use middle::trans::meth;
use middle::trans::type_of::type_of_fn_from_ty;
use middle::trans::type_of;
use middle::trans::type_use;
+use middle::trans::intrinsic;
use middle::ty;
use middle::ty::{FnSig};
use middle::typeck;
}
ast_map::node_foreign_item(i, _, _, _) => {
let d = mk_lldecl();
- foreign::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
- ref_id);
+ intrinsic::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
+ ref_id);
d
}
ast_map::node_variant(ref v, enum_item, _) => {
sub_path,
"get_disr");
- let llfty = type_of_fn(ccx, [opaqueptrty], ty::mk_int());
+ let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
let fcx = new_fn_ctxt(ccx,
~[],
Ignore => bcx,
SaveIn(lldest) => {
unsafe {
- let bytes = str_lit.len(); // count null-terminator too
+ let bytes = str_lit.len();
let llbytes = C_uint(bcx.ccx(), bytes);
let llcstr = C_cstr(bcx.ccx(), str_lit);
let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p().to_ref());
pub fn named_struct(name: &str) -> Type {
let ctx = base::task_llcx();
- ty!(name.to_c_str().with_ref(|s| llvm::LLVMStructCreateNamed(ctx, s)))
+ ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s)))
}
pub fn empty_struct() -> Type {
use middle::trans::adt;
use middle::trans::common::*;
+use middle::trans::foreign;
use middle::ty;
use util::ppaux;
use syntax::ast;
use syntax::opt_vec;
-pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: &ty::t) -> bool {
- !ty::type_is_immediate(ccx.tcx, *arg_ty)
+pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: ty::t) -> bool {
+ !ty::type_is_immediate(ccx.tcx, arg_ty)
}
-pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: &ty::t) -> Type {
- let llty = type_of(ccx, *arg_ty);
+pub fn return_uses_outptr(tcx: ty::ctxt, ty: ty::t) -> bool {
+ !ty::type_is_immediate(tcx, ty)
+}
+
+pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: ty::t) -> Type {
+ let llty = type_of(ccx, arg_ty);
if arg_is_indirect(ccx, arg_ty) {
llty.ptr_to()
} else {
pub fn type_of_explicit_args(ccx: &mut CrateContext,
inputs: &[ty::t]) -> ~[Type] {
- inputs.map(|arg_ty| type_of_explicit_arg(ccx, arg_ty))
+ inputs.map(|&arg_ty| type_of_explicit_arg(ccx, arg_ty))
}
-pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) -> Type {
+pub fn type_of_rust_fn(cx: &mut CrateContext,
+ inputs: &[ty::t],
+ output: ty::t) -> Type {
let mut atys: ~[Type] = ~[];
// Arg 0: Output pointer.
// (if the output type is non-immediate)
- let output_is_immediate = ty::type_is_immediate(cx.tcx, output);
+ let use_out_pointer = return_uses_outptr(cx.tcx, output);
let lloutputtype = type_of(cx, output);
- if !output_is_immediate {
+ if use_out_pointer {
atys.push(lloutputtype.ptr_to());
}
atys.push_all(type_of_explicit_args(cx, inputs));
// Use the output as the actual return value if it's immediate.
- if output_is_immediate && !ty::type_is_nil(output) {
+ if !use_out_pointer && !ty::type_is_voidish(output) {
Type::func(atys, &lloutputtype)
} else {
Type::func(atys, &Type::void())
// Given a function type and a count of ty params, construct an llvm type
pub fn type_of_fn_from_ty(cx: &mut CrateContext, fty: ty::t) -> Type {
- match ty::get(fty).sty {
- ty::ty_closure(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
- ty::ty_bare_fn(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
+ return match ty::get(fty).sty {
+ ty::ty_closure(ref f) => {
+ type_of_rust_fn(cx, f.sig.inputs, f.sig.output)
+ }
+ ty::ty_bare_fn(ref f) => {
+ if f.abis.is_rust() || f.abis.is_intrinsic() {
+ type_of_rust_fn(cx, f.sig.inputs, f.sig.output)
+ } else {
+ foreign::lltype_for_foreign_fn(cx, fty)
+ }
+ }
_ => {
cx.sess.bug("type_of_fn_from_ty given non-closure, non-bare-fn")
}
- }
+ };
}
// A "sizing type" is an LLVM type, the size and alignment of which are
Type::array(&type_of(cx, mt.ty), n as u64)
}
- ty::ty_bare_fn(_) => type_of_fn_from_ty(cx, t).ptr_to(),
+ ty::ty_bare_fn(_) => {
+ type_of_fn_from_ty(cx, t).ptr_to()
+ }
ty::ty_closure(_) => {
let ty = type_of_fn_from_ty(cx, t);
Type::func_pair(cx, &ty)
// Type utilities
+pub fn type_is_voidish(ty: t) -> bool {
+ //! "nil" and "bot" are void types in that they represent 0 bits of information
+ type_is_nil(ty) || type_is_bot(ty)
+}
+
pub fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil }
pub fn type_is_bot(ty: t) -> bool {
if ty::type_is_error(e) || ty::type_is_error(a) {
return;
}
- match self.fn_kind {
- DoBlock if ty::type_is_bool(e) && ty::type_is_nil(a) =>
- // If we expected bool and got ()...
- self.tcx().sess.span_err(sp, fmt!("Do-block body must \
- return %s, but returns () here. Perhaps you meant \
- to write a `for`-loop?",
- ppaux::ty_to_str(self.tcx(), e))),
- _ => self.infcx().report_mismatched_types(sp, e, a, err)
- }
+ self.infcx().report_mismatched_types(sp, e, a, err)
}
pub fn report_mismatched_types(&self,
use middle::typeck::infer::{TypeTrace};
use util::common::indent;
-use std::result::{iter_vec2, map_vec2};
+use std::result;
use std::vec;
use syntax::ast::{Onceness, purity};
use syntax::ast;
// variance.
if vec::same_length(as_, bs) {
- iter_vec2(as_, bs, |a, b| {
- eq_tys(this, *a, *b)
- }).then(|| Ok(as_.to_owned()) )
+ result::fold_(as_.iter().zip(bs.iter())
+ .map(|(a, b)| eq_tys(this, *a, *b)))
+ .then(|| Ok(as_.to_owned()))
} else {
Err(ty::terr_ty_param_size(
expected_found(this, as_.len(), bs.len())))
{
fn argvecs<C:Combine>(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<~[ty::t]> {
if vec::same_length(a_args, b_args) {
- map_vec2(a_args, b_args, |a, b| this.args(*a, *b))
+ result::collect(a_args.iter().zip(b_args.iter())
+ .map(|(a, b)| this.args(*a, *b)))
} else {
Err(ty::terr_arg_count)
}
(&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
if as_.len() == bs.len() {
- map_vec2(*as_, *bs, |a, b| this.tys(*a, *b) )
- .chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
+ result::collect(as_.iter().zip(bs.iter())
+ .map(|(a, b)| this.tys(*a, *b)))
+ .chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
} else {
Err(ty::terr_tuple_size(
expected_found(this, as_.len(), bs.len())))
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
+// Rustc tasks always run on a fixed_stack_segment, so code in this
+// module can call C functions (in particular, LLVM functions) with
+// impunity.
+#[allow(cstack)];
+
extern mod extra;
extern mod syntax;
pub mod reachable;
pub mod graph;
pub mod cfg;
+ pub mod stack_check;
}
pub mod front {
let sess = build_session(sopts, demitter);
let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
- let cfg = build_configuration(sess, binary, &input);
+ let cfg = build_configuration(sess);
let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
parse_pretty(sess, a)
};
let xs = [
~"the compiler hit an unexpected failure path. \
this is a bug",
- ~"try running with RUST_LOG=rustc=1,::rt::backtrace \
+ ~"try running with RUST_LOG=rustc=1 \
to get further details and report the results \
to github.com/mozilla/rust/issues"
];
ty_to_str(tcx, *self)
}
}
+
+impl Repr for AbiSet {
+ fn repr(&self, _tcx: ctxt) -> ~str {
+ self.to_str()
+ }
+}
+
+impl UserString for AbiSet {
+ fn user_string(&self, _tcx: ctxt) -> ~str {
+ self.to_str()
+ }
+}
//! AST-parsing helpers
-
-use rustc::driver::driver::{file_input, str_input};
use rustc::driver::driver;
use rustc::driver::session;
use syntax::ast;
pub fn from_file_sess(sess: session::Session, file: &Path) -> @ast::Crate {
parse::parse_crate_from_file(
- file, cfg(sess, file_input((*file).clone())), sess.parse_sess)
+ file, cfg(sess), sess.parse_sess)
}
pub fn from_str_sess(sess: session::Session, source: @str) -> @ast::Crate {
parse::parse_crate_from_source_str(
- @"-", source, cfg(sess, str_input(source)), sess.parse_sess)
+ @"-", source, cfg(sess), sess.parse_sess)
}
-fn cfg(sess: session::Session, input: driver::input) -> ast::CrateConfig {
- driver::build_configuration(sess, @"rustdoc", &input)
+fn cfg(sess: session::Session) -> ast::CrateConfig {
+ driver::build_configuration(sess)
}
+
// Stage 1: parse the input and filter it into the program (as necessary)
//
debug!("parsing: %s", input);
- let crate = parse_input(sess, binary, input);
+ let crate = parse_input(sess, binary);
let mut to_run = ~[]; // statements to run (emitted back into code)
let new_locals = @mut ~[]; // new locals being defined
let mut result = None; // resultant expression (to print via pp)
let test = program.test_code(input, &result, *new_locals);
debug!("testing with ^^^^^^ %?", (||{ println(test) })());
let dinput = driver::str_input(test.to_managed());
- let cfg = driver::build_configuration(sess, binary, &dinput);
+ let cfg = driver::build_configuration(sess);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &dinput);
let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
let code = program.code(input, &result);
debug!("actually running ^^^^^^ %?", (||{ println(code) })());
let input = driver::str_input(code.to_managed());
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
let sess = driver::build_session(options, diagnostic::emit);
//
return (program, jit::consume_engine());
- fn parse_input(sess: session::Session, binary: @str,
- input: &str) -> @ast::Crate {
+ fn parse_input(sess: session::Session, input: &str) -> @ast::Crate {
let code = fmt!("fn main() {\n %s \n}", input);
let input = driver::str_input(code.to_managed());
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
driver::phase_1_parse_input(sess, cfg.clone(), &input)
}
let input = driver::file_input(src_path.clone());
let sess = driver::build_session(options, diagnostic::emit);
*sess.building_library = true;
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let outputs = driver::build_output_filenames(
&input, &None, &None, [], sess);
// If the library already exists and is newer than the source
}
pub fn main() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let args = os::args();
let input = io::stdin();
let out = io::stdout();
};
let input = driver::file_input(script);
let sess = driver::build_session(options, diagnostic::emit);
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
let crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
let work_dir = build_pkg_id_in_workspace(id, workspace);
fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) {
let cwd = (*cwd).clone();
let mut prog = run::Process::new("git", args, run::ProcessOptions {
- env: env.map(|v| v.slice(0, v.len())),
+ env: env,
dir: Some(&cwd),
in_fd: None,
out_fd: None,
assert!(os::path_is_dir(&*cwd));
let cwd = (*cwd).clone();
let mut prog = run::Process::new(cmd, args, run::ProcessOptions {
- env: env.map(|v| v.slice(0, v.len())),
+ env: env,
dir: Some(&cwd),
in_fd: None,
out_fd: None,
// use command_line_test_with_env
let mut prog = run::Process::new("rustpkg",
[~"install", ~"foo"],
- run::ProcessOptions { env: Some(&[(~"RUST_LOG",
+// This should actually extend the environment; then we can probably
+// un-ignore it
+ run::ProcessOptions { env: Some(~[(~"RUST_LOG",
~"rustpkg"),
(~"RUST_PATH",
dir_for_path.to_str())]),
~"--sysroot", test_sysroot().to_str(),
~"-o", exec_file.to_str()],
run::ProcessOptions {
- env: env.map(|v| v.slice(0, v.len())),
+ env: env,
dir: Some(&dir),
in_fd: None,
out_fd: None,
// Infer dependencies that rustpkg needs to build, by scanning for
// `extern mod` directives.
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
#[cfg(windows)]
pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
/* FIXME (#1768): Investigate how to do this on win32
Node wraps symlinks by having a .bat,
but that won't work with minGW. */
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn link_exe(src: &Path, dest: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
use std::c_str::ToCStr;
use std::libc;
unsafe {
- do src.to_c_str().with_ref |src_buf| {
- do dest.to_c_str().with_ref |dest_buf| {
+ do src.with_c_str |src_buf| {
+ do dest.with_c_str |dest_buf| {
libc::link(src_buf, dest_buf) == 0 as libc::c_int &&
libc::chmod(dest_buf, 755) == 0 as libc::c_int
}
* Sets the length of a vector
*
* This will explicitly set the size of the vector, without actually
- * modifing its buffers, so it is up to the caller to ensure that
+ * modifying its buffers, so it is up to the caller to ensure that
* the vector is actually the specified size.
*/
#[inline]
mod test {
use super::*;
use prelude::*;
+ use bh = extra::test::BenchHarness;
#[test]
fn test() {
assert_eq!(to_managed([@"abc", @"123"]), @[@"abc", @"123"]);
assert_eq!(to_managed([@[42]]), @[@[42]]);
}
+
+ #[bench]
+ fn bench_capacity(b: &mut bh) {
+ let x = @[1, 2, 3];
+ do b.iter {
+ capacity(x);
+ }
+ }
+
+ #[bench]
+ fn bench_build_sized(b: &mut bh) {
+ let len = 64;
+ do b.iter {
+ build_sized(len, |push| for i in range(0, 1024) { push(i) });
+ }
+ }
+
+ #[bench]
+ fn bench_build(b: &mut bh) {
+ do b.iter {
+ for i in range(0, 95) {
+ build(|push| push(i));
+ }
+ }
+ }
+
+ #[bench]
+ fn bench_append(b: &mut bh) {
+ let lhs = @[7, ..128];
+ let rhs = range(0, 256).to_owned_vec();
+ do b.iter {
+ append(lhs, rhs);
+ }
+ }
+
+ #[bench]
+ fn bench_map(b: &mut bh) {
+ let elts = range(0, 256).to_owned_vec();
+ do b.iter {
+ map(elts, |x| x*2);
+ }
+ }
+
+ #[bench]
+ fn bench_from_fn(b: &mut bh) {
+ do b.iter {
+ from_fn(1024, |x| x);
+ }
+ }
+
+ #[bench]
+ fn bench_from_elem(b: &mut bh) {
+ do b.iter {
+ from_elem(1024, 0u64);
+ }
+ }
+
+ #[bench]
+ fn bench_to_managed_move(b: &mut bh) {
+ do b.iter {
+ let elts = range(0, 1024).to_owned_vec(); // yikes! can't move out of capture, though
+ to_managed_move(elts);
+ }
+ }
+
+ #[bench]
+ fn bench_to_managed(b: &mut bh) {
+ let elts = range(0, 1024).to_owned_vec();
+ do b.iter {
+ to_managed(elts);
+ }
+ }
+
+ #[bench]
+ fn bench_clone(b: &mut bh) {
+ let elts = to_managed(range(0, 1024).to_owned_vec());
+ do b.iter {
+ elts.clone();
+ }
+ }
}
Also, a few conversion functions: `to_bit` and `to_str`.
-Finally, some inquries into the nature of truth: `is_true` and `is_false`.
+Finally, some inquiries into the nature of truth: `is_true` and `is_false`.
*/
// except according to those terms.
use cast;
-use iterator::Iterator;
+use iterator::{Iterator,range};
use libc;
use ops::Drop;
use option::{Option, Some, None};
use ptr::RawPtr;
use ptr;
use str::StrSlice;
-use vec::ImmutableVector;
+use vec::{ImmutableVector,CopyableVector};
+use container::Container;
+
+/// Resolution options for the `null_byte` condition
+pub enum NullByteResolution {
+ /// Truncate at the null byte
+ Truncate,
+ /// Use a replacement byte
+ ReplaceWith(libc::c_char)
+}
+
+condition! {
+ // this should be &[u8] but there's a lifetime issue
+ null_byte: (~[u8]) -> super::NullByteResolution;
+}
/// The representation of a C String.
///
}
/// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
+ /// Any ownership of the buffer by the `CString` wrapper is forgotten.
pub unsafe fn unwrap(self) -> *libc::c_char {
let mut c_str = self;
c_str.owns_buffer_ = false;
///
/// Fails if the CString is null.
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
+ #[fixed_stack_segment]; #[inline(never)];
if self.buf.is_null() { fail!("CString is null!"); }
unsafe {
let len = libc::strlen(self.buf) as uint;
}
/// Return a CString iterator.
- fn iter<'a>(&'a self) -> CStringIterator<'a> {
+ pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
CStringIterator {
ptr: self.buf,
lifetime: unsafe { cast::transmute(self.buf) },
impl Drop for CString {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
if self.owns_buffer_ {
unsafe {
libc::free(self.buf as *libc::c_void)
/// A generic trait for converting a value to a CString.
pub trait ToCStr {
- /// Create a C String.
+ /// Copy the receiver into a CString.
+ ///
+ /// # Failure
+ ///
+ /// Raises the `null_byte` condition if the receiver has an interior null.
fn to_c_str(&self) -> CString;
+
+ /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
+ unsafe fn to_c_str_unchecked(&self) -> CString;
+
+ /// Work with a temporary CString constructed from the receiver.
+ /// The provided `*libc::c_char` will be freed immediately upon return.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// let s = "PATH".with_c_str(|path| libc::getenv(path))
+ /// ~~~
+ ///
+ /// # Failure
+ ///
+ /// Raises the `null_byte` condition if the receiver has an interior null.
+ #[inline]
+ fn with_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
+ self.to_c_str().with_ref(f)
+ }
+
+ /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
+ #[inline]
+ unsafe fn with_c_str_unchecked<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
+ self.to_c_str_unchecked().with_ref(f)
+ }
}
impl<'self> ToCStr for &'self str {
fn to_c_str(&self) -> CString {
self.as_bytes().to_c_str()
}
+
+ #[inline]
+ unsafe fn to_c_str_unchecked(&self) -> CString {
+ self.as_bytes().to_c_str_unchecked()
+ }
}
impl<'self> ToCStr for &'self [u8] {
fn to_c_str(&self) -> CString {
- do self.as_imm_buf |self_buf, self_len| {
- unsafe {
- let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
- if buf.is_null() {
- fail!("failed to allocate memory!");
+ #[fixed_stack_segment]; #[inline(never)];
+ let mut cs = unsafe { self.to_c_str_unchecked() };
+ do cs.with_mut_ref |buf| {
+ for i in range(0, self.len()) {
+ unsafe {
+ let p = buf.offset_inbounds(i as int);
+ if *p == 0 {
+ match null_byte::cond.raise(self.to_owned()) {
+ Truncate => break,
+ ReplaceWith(c) => *p = c
+ }
+ }
}
+ }
+ }
+ cs
+ }
- ptr::copy_memory(buf, self_buf, self_len);
- *ptr::mut_offset(buf, self_len as int) = 0;
-
- CString::new(buf as *libc::c_char, true)
+ unsafe fn to_c_str_unchecked(&self) -> CString {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.as_imm_buf |self_buf, self_len| {
+ let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
+ if buf.is_null() {
+ fail!("failed to allocate memory!");
}
+
+ ptr::copy_memory(buf, self_buf, self_len);
+ *ptr::mut_offset(buf, self_len as int) = 0;
+
+ CString::new(buf as *libc::c_char, true)
}
}
}
#[test]
fn test_unwrap() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let c_str = "hello".to_c_str();
unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
}
#[test]
fn test_with_ref() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let c_str = "hello".to_c_str();
let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
assert!(!c_str.is_null());
assert_eq!(iter.next(), Some('o' as libc::c_char));
assert_eq!(iter.next(), None);
}
+
+ #[test]
+ #[ignore(cfg(windows))]
+ fn test_to_c_str_fail() {
+ use c_str::null_byte::cond;
+
+ let mut error_happened = false;
+ do cond.trap(|err| {
+ assert_eq!(err, bytes!("he", 0, "llo").to_owned())
+ error_happened = true;
+ Truncate
+ }).inside {
+ "he\x00llo".to_c_str()
+ };
+ assert!(error_happened);
+
+ do cond.trap(|_| {
+ ReplaceWith('?' as libc::c_char)
+ }).inside(|| "he\x00llo".to_c_str()).with_ref |buf| {
+ unsafe {
+ assert_eq!(*buf.offset(0), 'h' as libc::c_char);
+ assert_eq!(*buf.offset(1), 'e' as libc::c_char);
+ assert_eq!(*buf.offset(2), '?' as libc::c_char);
+ assert_eq!(*buf.offset(3), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(4), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(5), 'o' as libc::c_char);
+ assert_eq!(*buf.offset(6), 0);
+ }
+ }
+ }
+
+ #[test]
+ fn test_to_c_str_unchecked() {
+ unsafe {
+ do "he\x00llo".to_c_str_unchecked().with_ref |buf| {
+ assert_eq!(*buf.offset(0), 'h' as libc::c_char);
+ assert_eq!(*buf.offset(1), 'e' as libc::c_char);
+ assert_eq!(*buf.offset(2), 0);
+ assert_eq!(*buf.offset(3), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(4), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(5), 'o' as libc::c_char);
+ assert_eq!(*buf.offset(6), 0);
+ }
+ }
+ }
}
use clone::Clone;
use container::Container;
use cmp::Eq;
-use iterator::Iterator;
+use iterator::{Iterator, FilterMap};
use result::Result;
use result;
use str::StrSlice;
}
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Extracts from a vector of either all the left values
-pub fn lefts<L: Clone, R>(eithers: &[Either<L, R>]) -> ~[L] {
- do vec::build_sized(eithers.len()) |push| {
- for elt in eithers.iter() {
- match *elt {
- Left(ref l) => { push((*l).clone()); }
- _ => { /* fallthrough */ }
- }
+/// An iterator yielding the `Left` values of its source
+pub type Lefts<L, R, Iter> = FilterMap<'static, Either<L, R>, L, Iter>;
+
+/// An iterator yielding the `Right` values of its source
+pub type Rights<L, R, Iter> = FilterMap<'static, Either<L, R>, R, Iter>;
+
+/// Extracts all the left values
+pub fn lefts<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter)
+ -> Lefts<L, R, Iter> {
+ do eithers.filter_map |elt| {
+ match elt {
+ Left(x) => Some(x),
+ _ => None,
}
}
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Extracts from a vector of either all the right values
-pub fn rights<L, R: Clone>(eithers: &[Either<L, R>]) -> ~[R] {
- do vec::build_sized(eithers.len()) |push| {
- for elt in eithers.iter() {
- match *elt {
- Right(ref r) => { push((*r).clone()); }
- _ => { /* fallthrough */ }
- }
+/// Extracts all the right values
+pub fn rights<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter)
+ -> Rights<L, R, Iter> {
+ do eithers.filter_map |elt| {
+ match elt {
+ Right(x) => Some(x),
+ _ => None,
}
}
}
+
// FIXME: #8228 Replaceable by an external iterator?
/// Extracts from a vector of either all the left values and right values
///
/// Returns a structure containing a vector of left values and a vector of
/// right values.
pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) {
- let mut lefts: ~[L] = ~[];
- let mut rights: ~[R] = ~[];
+ let n_lefts = eithers.iter().count(|elt| elt.is_left());
+ let mut lefts = vec::with_capacity(n_lefts);
+ let mut rights = vec::with_capacity(eithers.len() - n_lefts);
for elt in eithers.move_iter() {
match elt {
Left(l) => lefts.push(l),
#[test]
fn test_lefts() {
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
- let result = lefts(input);
+ let result = lefts(input.move_iter()).to_owned_vec();
assert_eq!(result, ~[10, 12, 14]);
}
#[test]
fn test_lefts_none() {
let input: ~[Either<int, int>] = ~[Right(10), Right(10)];
- let result = lefts(input);
+ let result = lefts(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
#[test]
fn test_lefts_empty() {
let input: ~[Either<int, int>] = ~[];
- let result = lefts(input);
+ let result = lefts(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
#[test]
fn test_rights() {
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
- let result = rights(input);
+ let result = rights(input.move_iter()).to_owned_vec();
assert_eq!(result, ~[11, 13]);
}
#[test]
fn test_rights_none() {
let input: ~[Either<int, int>] = ~[Left(10), Left(10)];
- let result = rights(input);
+ let result = rights(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
#[test]
fn test_rights_empty() {
let input: ~[Either<int, int>] = ~[];
- let result = rights(input);
+ let result = rights(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
Because formatting is done via traits, there is no requirement that the
`d` format actually takes an `int`, but rather it simply requires a type which
ascribes to the `Signed` formatting trait. There are various parameters which do
-require a particular type, however. Namely if the sytnax `{:.*s}` is used, then
+require a particular type, however. Namely if the syntax `{:.*s}` is used, then
the number of characters to print from the string precedes the actual string and
must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is
illegal to reference an argument as such. For example, this is another invalid
## Internationalization
The formatting syntax supported by the `ifmt!` extension supports
-internationalization by providing "methods" which execute various differnet
+internationalization by providing "methods" which execute various different
outputs depending on the input. The syntax and methods provided are similar to
other internationalization systems, so again nothing should seem alien.
Currently two methods are supported by this extension: "select" and "plural".
priv value: &'self util::Void,
}
+/// When a format is not otherwise specified, types are formatted by ascribing
+/// to this trait. There is not an explicit way of selecting this trait to be
+/// used for formatting, it is only if no other format is specified.
+#[allow(missing_doc)]
+pub trait Default { fn fmt(&Self, &mut Formatter); }
+
+/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Bool { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `c` character
#[allow(missing_doc)]
pub trait Char { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `i` and `d` characters
#[allow(missing_doc)]
pub trait Signed { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `u` character
#[allow(missing_doc)]
pub trait Unsigned { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `o` character
#[allow(missing_doc)]
pub trait Octal { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Binary { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `x` character
#[allow(missing_doc)]
pub trait LowerHex { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `X` character
#[allow(missing_doc)]
pub trait UpperHex { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `s` character
#[allow(missing_doc)]
pub trait String { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `?` character
#[allow(missing_doc)]
pub trait Poly { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `p` character
#[allow(missing_doc)]
pub trait Pointer { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `f` character
#[allow(missing_doc)]
pub trait Float { fn fmt(&Self, &mut Formatter); }
}
}
-impl<'self> String for &'self str {
- fn fmt(s: & &'self str, f: &mut Formatter) {
- f.pad(*s);
+impl<'self, T: str::Str> String for T {
+ fn fmt(s: &T, f: &mut Formatter) {
+ f.pad(s.as_slice());
}
}
}
}
+// Implementation of Default for various core types
+
+macro_rules! delegate(($ty:ty to $other:ident) => {
+ impl<'self> Default for $ty {
+ fn fmt(me: &$ty, f: &mut Formatter) {
+ $other::fmt(me, f)
+ }
+ }
+})
+delegate!(int to Signed)
+delegate!( i8 to Signed)
+delegate!(i16 to Signed)
+delegate!(i32 to Signed)
+delegate!(i64 to Signed)
+delegate!(uint to Unsigned)
+delegate!( u8 to Unsigned)
+delegate!( u16 to Unsigned)
+delegate!( u32 to Unsigned)
+delegate!( u64 to Unsigned)
+delegate!(@str to String)
+delegate!(~str to String)
+delegate!(&'self str to String)
+delegate!(bool to Bool)
+delegate!(char to Char)
+delegate!(float to Float)
+delegate!(f32 to Float)
+delegate!(f64 to Float)
+
+impl<T> Default for *const T {
+ fn fmt(me: &*const T, f: &mut Formatter) { Pointer::fmt(me, f) }
+}
+
// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
// it's a lot easier than creating all of the rt::Piece structures here.
ArgumentNext, ArgumentIs(uint), ArgumentNamed(&'self str)
}
-/// Enum of alignments which are supoprted.
+/// Enum of alignments which are supported.
#[deriving(Eq)]
pub enum Alignment { AlignLeft, AlignRight, AlignUnknown }
}
}
// Finally the actual format specifier
- spec.ty = self.word();
+ if self.consume('?') {
+ spec.ty = "?";
+ } else {
+ spec.ty = self.word();
+ }
return spec;
}
use uint;
+ // Hash just the bytes of the slice, without length prefix
+ struct Bytes<'self>(&'self [u8]);
+ impl<'self> IterBytes for Bytes<'self> {
+ fn iter_bytes(&self, _lsb0: bool, f: &fn(&[u8]) -> bool) -> bool {
+ f(**self)
+ }
+ }
+
#[test]
fn test_siphash() {
let vecs : [[u8, ..8], ..64] = [
while t < 64 {
debug!("siphash test %?", t);
let vec = u8to64_le!(vecs[t], 0);
- let out = buf.hash_keyed(k0, k1);
+ let out = Bytes(buf.as_slice()).hash_keyed(k0, k1);
debug!("got %?, expected %?", out, vec);
assert_eq!(vec, out);
fn test_float_hashes_of_zero() {
assert_eq!(0.0.hash(), (-0.0).hash());
}
+
+ #[test]
+ fn test_hash_no_concat_alias() {
+ let s = ("aa", "bb");
+ let t = ("aabb", "");
+ let u = ("a", "abb");
+
+ let v = (&[1u8], &[0u8, 0], &[0u8]);
+ let w = (&[1u8, 0, 0, 0], &[], &[]);
+
+ assert!(v != w);
+ assert!(s.hash() != t.hash() && s.hash() != u.hash());
+ assert!(v.hash() != w.hash());
+ }
}
}
}
-impl<K: Eq + Hash, V, T: Iterator<(K, V)>> FromIterator<(K, V), T> for HashMap<K, V> {
- fn from_iterator(iter: &mut T) -> HashMap<K, V> {
+impl<K: Eq + Hash, V> FromIterator<(K, V)> for HashMap<K, V> {
+ fn from_iterator<T: Iterator<(K, V)>>(iter: &mut T) -> HashMap<K, V> {
let (lower, _) = iter.size_hint();
let mut map = HashMap::with_capacity(lower);
map.extend(iter);
}
}
-impl<K: Eq + Hash, V, T: Iterator<(K, V)>> Extendable<(K, V), T> for HashMap<K, V> {
- fn extend(&mut self, iter: &mut T) {
+impl<K: Eq + Hash, V> Extendable<(K, V)> for HashMap<K, V> {
+ fn extend<T: Iterator<(K, V)>>(&mut self, iter: &mut T) {
for (k, v) in *iter {
self.insert(k, v);
}
}
}
-impl<K: Eq + Hash, T: Iterator<K>> FromIterator<K, T> for HashSet<K> {
- fn from_iterator(iter: &mut T) -> HashSet<K> {
+impl<K: Eq + Hash> FromIterator<K> for HashSet<K> {
+ fn from_iterator<T: Iterator<K>>(iter: &mut T) -> HashSet<K> {
let (lower, _) = iter.size_hint();
let mut set = HashSet::with_capacity(lower);
set.extend(iter);
}
}
-impl<K: Eq + Hash, T: Iterator<K>> Extendable<K, T> for HashSet<K> {
- fn extend(&mut self, iter: &mut T) {
+impl<K: Eq + Hash> Extendable<K> for HashSet<K> {
+ fn extend<T: Iterator<K>>(&mut self, iter: &mut T) {
for k in *iter {
self.insert(k);
}
impl Reader for *libc::FILE {
fn read(&self, bytes: &mut [u8], len: uint) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do bytes.as_mut_buf |buf_p, buf_len| {
assert!(buf_len >= len);
}
}
fn read_byte(&self) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fgetc(*self) as int
}
}
fn eof(&self) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return libc::feof(*self) != 0 as c_int;
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
}
}
fn tell(&self) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return libc::ftell(*self) as uint;
}
impl Drop for FILERes {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fclose(self.f);
}
* # Example
*
* ~~~ {.rust}
-* let stdin = core::io::stdin();
+* let stdin = std::io::stdin();
* let line = stdin.read_line();
-* core::io::print(line);
+* std::io::print(line);
* ~~~
*/
pub fn stdin() -> @Reader {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
@rustrt::rust_get_stdin() as @Reader
}
}
pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
- let f = do path.to_c_str().with_ref |pathbuf| {
- do "rb".to_c_str().with_ref |modebuf| {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ let f = do path.with_c_str |pathbuf| {
+ do "rb".with_c_str |modebuf| {
unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) }
}
};
impl Writer for *libc::FILE {
fn write(&self, v: &[u8]) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do v.as_imm_buf |vbuf, len| {
let nout = libc::fwrite(vbuf as *c_void,
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
}
}
fn tell(&self) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::ftell(*self) as uint
}
}
fn flush(&self) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fflush(*self) as int
}
}
fn get_type(&self) -> WriterType {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let fd = libc::fileno(*self);
if libc::isatty(fd) == 0 { File }
impl Writer for fd_t {
fn write(&self, v: &[u8]) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut count = 0u;
do v.as_imm_buf |vbuf, len| {
}
fn flush(&self) -> int { 0 }
fn get_type(&self) -> WriterType {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
if libc::isatty(*self) == 0 { File } else { Screen }
}
impl Drop for FdRes {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::close(self.fd);
}
pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
-> Result<@Writer, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[cfg(windows)]
fn wb() -> c_int {
(O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
}
}
let fd = unsafe {
- do path.to_c_str().with_ref |pathbuf| {
+ do path.with_c_str |pathbuf| {
libc::open(pathbuf, fflags, (S_IRUSR | S_IWUSR) as c_int)
}
};
/// (8 bytes).
fn write_le_f64(&self, f: f64);
- /// Write a litten-endian IEEE754 single-precision floating-point
+ /// Write a little-endian IEEE754 single-precision floating-point
/// (4 bytes).
fn write_le_f32(&self, f: f32);
// FIXME: fileflags // #2004
pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
- let f = do path.to_c_str().with_ref |pathbuf| {
- do "w".to_c_str().with_ref |modebuf| {
+ let f = do path.with_c_str |pathbuf| {
+ do "w".with_c_str |modebuf| {
libc::fopen(pathbuf, modebuf)
}
};
* # Example
*
* ~~~ {.rust}
-* let stdout = core::io::stdout();
+* let stdout = std::io::stdout();
* stdout.write_str("hello\n");
* ~~~
*/
* # Example
*
* ~~~ {.rust}
-* let stderr = core::io::stderr();
+* let stderr = std::io::stderr();
* stderr.write_str("hello\n");
* ~~~
*/
blk: &fn(v: Res<*libc::FILE>)) {
blk(Res::new(Arg {
val: file.f, opt_level: opt_level,
- fsync_fn: |file, l| {
- unsafe {
- os::fsync_fd(libc::fileno(*file), l) as int
- }
- }
+ fsync_fn: |file, l| fsync_fd(fileno(*file), l)
}));
+
+ fn fileno(stream: *libc::FILE) -> libc::c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::fileno(stream) }
+ }
}
// fsync fd after executing blk
blk: &fn(v: Res<fd_t>)) {
blk(Res::new(Arg {
val: fd.fd, opt_level: opt_level,
- fsync_fn: |fd, l| os::fsync_fd(*fd, l) as int
+ fsync_fn: |fd, l| fsync_fd(*fd, l)
}));
}
+ fn fsync_fd(fd: libc::c_int, level: Level) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ os::fsync_fd(fd, level) as int
+ }
+
// Type of objects that may want to fsync
pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
use uint;
/// Conversion from an `Iterator`
-pub trait FromIterator<A, T: Iterator<A>> {
+pub trait FromIterator<A> {
/// Build a container with elements from an external iterator.
- fn from_iterator(iterator: &mut T) -> Self;
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> Self;
}
/// A type growable from an `Iterator` implementation
-pub trait Extendable<A, T: Iterator<A>>: FromIterator<A, T> {
+pub trait Extendable<A>: FromIterator<A> {
/// Extend a container with the elements yielded by an iterator
- fn extend(&mut self, iterator: &mut T);
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T);
}
/// An interface for dealing with "external iterators". These types of iterators
/// assert!(it.peek().is_none());
/// assert!(it.next().is_none());
/// ~~~
+ #[inline]
fn peekable(self) -> Peekable<A, Self> {
Peekable{iter: self, peeked: None}
}
/// assert!(a == b);
/// ~~~
#[inline]
- fn collect<B: FromIterator<A, Self>>(&mut self) -> B {
+ fn collect<B: FromIterator<A>>(&mut self) -> B {
FromIterator::from_iterator(self)
}
i
}
- /// Return the element that gives the maximum value from the specfied function
+ /// Return the element that gives the maximum value from the
+ /// specified function.
///
/// # Example
///
}).map_move(|(x, _)| x)
}
- /// Return the element that gives the minimum value from the specfied function
+ /// Return the element that gives the minimum value from the
+ /// specified function.
///
/// # Example
///
}
}
-impl<'self, A, B, T: DoubleEndedIterator<A>> DoubleEndedIterator<B>
-for Map<'self, A, B, T> {
+impl<'self, A, B, T: DoubleEndedIterator<A>> DoubleEndedIterator<B> for Map<'self, A, B, T> {
#[inline]
fn next_back(&mut self) -> Option<B> {
let next = self.iter.next_back();
}
}
-impl<'self, A, B, T: RandomAccessIterator<A>> RandomAccessIterator<B>
-for Map<'self, A, B, T> {
+impl<'self, A, B, T: RandomAccessIterator<A>> RandomAccessIterator<B> for Map<'self, A, B, T> {
#[inline]
fn indexable(&self) -> uint {
self.iter.indexable()
}
impl<A: Clone> Repeat<A> {
- /// Create a new `Repeat` that enlessly repeats the element `elt`.
+ /// Create a new `Repeat` that endlessly repeats the element `elt`.
#[inline]
pub fn new(elt: A) -> Repeat<A> {
Repeat{element: elt}
They cannot be implemented by user code, but are instead implemented
by the compiler automatically for the types to which they apply.
-The 2 kinds are
-
-* Send - owned types and types containing owned types. These types
- may be transferred across task boundaries.
-
-* Freeze - types that are deeply immutable.
-
*/
-#[allow(missing_doc)];
-
+/// Types able to be transferred across task boundaries.
#[lang="send"]
pub trait Send {
// empty.
}
+/// Types that are either immutable or have inherited mutability.
#[lang="freeze"]
pub trait Freeze {
// empty.
}
+/// Types with a constant size known at compile-time.
#[lang="sized"]
pub trait Sized {
// Empty.
// doesn't link it correctly on i686, so we're going
// through a C function that mysteriously does work.
pub unsafe fn opendir(dirname: *c_char) -> *DIR {
+ #[fixed_stack_segment]; #[inline(never)];
rust_opendir(dirname)
}
pub unsafe fn readdir(dirp: *DIR) -> *dirent_t {
+ #[fixed_stack_segment]; #[inline(never)];
rust_readdir(dirp)
}
~~~{.rust}
use std::local_data;
-static key_int: local_data::Key<int> = &local_data::Key;
-static key_vector: local_data::Key<~[int]> = &local_data::Key;
+local_data_key!(key_int: int);
+local_data_key!(key_vector: ~[int]);
local_data::set(key_int, 3);
local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
use unstable::intrinsics;
$(
- #[inline]
+ #[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)
pub mod consts {
// FIXME (requires Issue #1433 to fix): replace with mathematical
// staticants from cmath.
- /// Archimedes' staticant
+ /// Archimedes' constant
pub static pi: f32 = 3.14159265358979323846264338327950288_f32;
/// pi/2.0
use unstable::intrinsics;
$(
- #[inline]
+ #[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)
#[allow(non_uppercase_statics)];
use num::{ToStrRadix, FromStrRadix};
-use num::{Zero, One, strconv};
+use num::{CheckedDiv, Zero, One, strconv};
use prelude::*;
use str;
pub static min_value: $T = (-1 as $T) << (bits - 1);
pub static max_value: $T = min_value - 1 as $T;
+impl CheckedDiv for $T {
+ #[inline]
+ fn checked_div(&self, v: &$T) -> Option<$T> {
+ if *v == 0 || (*self == min_value && *v == -1) {
+ None
+ } else {
+ Some(self / *v)
+ }
+ }
+}
+
enum Range { Closed, HalfOpen }
#[inline]
use super::*;
use prelude::*;
+ use int;
use i16;
use i32;
use i64;
fn test_range_step_zero_step() {
do range_step(0,10,0) |_i| { true };
}
+
+ #[test]
+ fn test_signed_checked_div() {
+ assert_eq!(10i.checked_div(&2), Some(5));
+ assert_eq!(5i.checked_div(&0), None);
+ assert_eq!(int::min_value.checked_div(&-1), None);
+ }
}
}))
}
/// Saturating math operations
-pub trait Saturating: Int {
+pub trait Saturating {
/// Saturating addition operator.
/// Returns a+b, saturating at the numeric bounds instead of overflowing.
+ fn saturating_add(self, v: Self) -> Self;
+
+ /// Saturating subtraction operator.
+ /// Returns a-b, saturating at the numeric bounds instead of overflowing.
+ fn saturating_sub(self, v: Self) -> Self;
+}
+
+impl<T: CheckedAdd+CheckedSub+Zero+Ord+Bounded> Saturating for T {
#[inline]
- fn saturating_add(self, v: Self) -> Self {
- let x = self + v;
- if v >= Zero::zero() {
- if x < self {
- // overflow
- Bounded::max_value::<Self>()
- } else { x }
- } else {
- if x > self {
- // underflow
- Bounded::min_value::<Self>()
- } else { x }
+ fn saturating_add(self, v: T) -> T {
+ match self.checked_add(&v) {
+ Some(x) => x,
+ None => if v >= Zero::zero() {
+ Bounded::max_value::<T>()
+ } else {
+ Bounded::min_value::<T>()
+ }
}
}
- /// Saturating subtraction operator.
- /// Returns a-b, saturating at the numeric bounds instead of overflowing.
#[inline]
- fn saturating_sub(self, v: Self) -> Self {
- let x = self - v;
- if v >= Zero::zero() {
- if x > self {
- // underflow
- Bounded::min_value::<Self>()
- } else { x }
- } else {
- if x < self {
- // overflow
- Bounded::max_value::<Self>()
- } else { x }
+ fn saturating_sub(self, v: T) -> T {
+ match self.checked_sub(&v) {
+ Some(x) => x,
+ None => if v >= Zero::zero() {
+ Bounded::min_value::<T>()
+ } else {
+ Bounded::max_value::<T>()
+ }
}
}
}
-impl Saturating for int {}
-impl Saturating for i8 {}
-impl Saturating for i16 {}
-impl Saturating for i32 {}
-impl Saturating for i64 {}
-impl Saturating for uint {}
-impl Saturating for u8 {}
-impl Saturating for u16 {}
-impl Saturating for u32 {}
-impl Saturating for u64 {}
-
pub trait CheckedAdd: Add<Self, Self> {
fn checked_add(&self, v: &Self) -> Option<Self>;
}
}
}
+pub trait CheckedDiv: Div<Self, Self> {
+ fn checked_div(&self, v: &Self) -> Option<Self>;
+}
+
/// Helper function for testing numeric operations
#[cfg(test)]
pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
use num::BitCount;
use num::{ToStrRadix, FromStrRadix};
-use num::{Zero, One, strconv};
+use num::{CheckedDiv, Zero, One, strconv};
use prelude::*;
use str;
pub static min_value: $T = 0 as $T;
pub static max_value: $T = 0 as $T - 1 as $T;
+impl CheckedDiv for $T {
+ #[inline]
+ fn checked_div(&self, v: &$T) -> Option<$T> {
+ if *v == 0 {
+ None
+ } else {
+ Some(self / *v)
+ }
+ }
+}
+
enum Range { Closed, HalfOpen }
#[inline]
fn test_range_step_zero_step_down() {
do range_step(0,-10,0) |_i| { true };
}
+
+ #[test]
+ fn test_unsigned_checked_div() {
+ assert_eq!(10u.checked_div(&2), Some(5));
+ assert_eq!(5u.checked_div(&0), None);
+ }
}
}))
/// Delegates to the libc close() function, returning the same return value.
pub fn close(fd: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::close(fd)
}
static BUF_BYTES : uint = 2048u;
pub fn getcwd() -> Path {
+ #[fixed_stack_segment]; #[inline(never)];
let mut buf = [0 as libc::c_char, ..BUF_BYTES];
do buf.as_mut_buf |buf, len| {
unsafe {
pub fn fill_utf16_buf_and_decode(f: &fn(*mut u16, DWORD) -> DWORD)
-> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut n = TMPBUF_SZ as DWORD;
let mut res = None;
}
}
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident ()) => (
+ extern {
+ fn $name();
+ }
+ )
+)
+}
+
/*
Accessing environment variables is not generally threadsafe.
Serialize access through a global lock.
};
}
- extern {
- #[fast_ffi]
- fn rust_take_env_lock();
- #[fast_ffi]
- fn rust_drop_env_lock();
- }
+ externfn!(fn rust_take_env_lock());
+ externfn!(fn rust_drop_env_lock());
}
/// Returns a vector of (variable, value) pairs for all the environment
unsafe {
#[cfg(windows)]
unsafe fn get_env_pairs() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::funcs::extra::kernel32::{
GetEnvironmentStringsA,
FreeEnvironmentStringsA
}
#[cfg(unix)]
unsafe fn get_env_pairs() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
extern {
fn rust_env_pairs() -> **libc::c_char;
}
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
- let s = do n.to_c_str().with_ref |buf| {
+ let s = do n.with_c_str |buf| {
libc::getenv(buf)
};
if s.is_null() {
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do with_env_lock {
use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
- do n.to_c_str().with_ref |nbuf| {
- do v.to_c_str().with_ref |vbuf| {
+ do n.with_c_str |nbuf| {
+ do v.with_c_str |vbuf| {
libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
}
}
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
pub fn unsetenv(n: &str) {
#[cfg(unix)]
fn _unsetenv(n: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
- do n.to_c_str().with_ref |nbuf| {
+ do n.with_c_str |nbuf| {
libc::funcs::posix01::unistd::unsetenv(nbuf);
}
}
}
#[cfg(windows)]
fn _unsetenv(n: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
}
pub fn fdopen(fd: c_int) -> *FILE {
- do "r".to_c_str().with_ref |modebuf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do "r".with_c_str |modebuf| {
unsafe {
libc::fdopen(fd, modebuf)
}
#[cfg(windows)]
pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::extra::msvcrt::*;
return commit(fd);
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::*;
match level {
#[cfg(target_os = "macos")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
use libc::consts::os::extra::*;
use libc::funcs::posix88::fcntl::*;
#[cfg(target_os = "freebsd")]
pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
use libc::funcs::posix01::unistd::*;
return fsync(fd);
#[cfg(unix)]
pub fn pipe() -> Pipe {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut fds = Pipe {input: 0 as c_int,
out: 0 as c_int };
#[cfg(windows)]
pub fn pipe() -> Pipe {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
// Windows pipes work subtly differently than unix pipes, and their
// inheritance has to be handled in a different way that I do not
// fully understand. Here we explicitly make the pipe non-inheritable,
// which means to pass it to a subprocess they need to be duplicated
- // first, as in core::run.
+ // first, as in std::run.
let mut fds = Pipe {input: 0 as c_int,
out: 0 as c_int };
let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
}
fn dup2(src: c_int, dst: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::dup2(src, dst)
}
#[cfg(target_os = "freebsd")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::readlink;
let mut path = [0 as c_char, .. TMPBUF_SZ];
do path.as_mut_buf |buf, len| {
- let len = do "/proc/self/exe".to_c_str().with_ref |proc_self_buf| {
+ let len = do "/proc/self/exe".with_c_str |proc_self_buf| {
readlink(proc_self_buf, buf, len as size_t) as uint
};
#[cfg(target_os = "macos")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do fill_charp_buf() |buf, sz| {
let mut sz = sz as u32;
#[cfg(windows)]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::fill_utf16_buf_and_decode;
do fill_utf16_buf_and_decode() |buf, sz| {
/// Indicates whether a path represents a directory
pub fn path_is_dir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- do p.to_c_str().with_ref |buf| {
+ do p.with_c_str |buf| {
rustrt::rust_path_is_dir(buf) != 0 as c_int
}
}
/// Indicates whether a path exists
pub fn path_exists(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- do p.to_c_str().with_ref |buf| {
+ do p.with_c_str |buf| {
rustrt::rust_path_exists(buf) != 0 as c_int
}
}
#[cfg(windows)]
fn mkdir(p: &Path, _mode: c_int) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
// FIXME: turn mode into something useful? #2623
#[cfg(unix)]
fn mkdir(p: &Path, mode: c_int) -> bool {
- do p.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do p.with_c_str |buf| {
unsafe {
libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
}
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
unsafe fn get_list(p: &Path) -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::{dirent_t};
use libc::{opendir, readdir, closedir};
extern {
let mut strings = ~[];
debug!("os::list_dir -- BEFORE OPENDIR");
- let dir_ptr = do p.to_c_str().with_ref |buf| {
+ let dir_ptr = do p.with_c_str |buf| {
opendir(buf)
};
}
#[cfg(windows)]
unsafe fn get_list(p: &Path) -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::consts::os::extra::INVALID_HANDLE_VALUE;
use libc::{wcslen, free};
use libc::funcs::extra::kernel32::{
#[cfg(windows)]
fn rmdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn rmdir(p: &Path) -> bool {
- do p.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do p.with_c_str |buf| {
unsafe {
libc::rmdir(buf) == (0 as c_int)
}
#[cfg(windows)]
fn chdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn chdir(p: &Path) -> bool {
- do p.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do p.with_c_str |buf| {
unsafe {
libc::chdir(buf) == (0 as c_int)
}
#[cfg(windows)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(from.to_str()) |fromp| {
#[cfg(unix)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- let istream = do from.to_c_str().with_ref |fromp| {
- do "rb".to_c_str().with_ref |modebuf| {
+ let istream = do from.with_c_str |fromp| {
+ do "rb".with_c_str |modebuf| {
libc::fopen(fromp, modebuf)
}
};
let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \
for source file");
- let ostream = do to.to_c_str().with_ref |top| {
- do "w+b".to_c_str().with_ref |modebuf| {
+ let ostream = do to.with_c_str |top| {
+ do "w+b".with_c_str |modebuf| {
libc::fopen(top, modebuf)
}
};
fclose(ostream);
// Give the new file the old file's permissions
- if do to.to_c_str().with_ref |to_buf| {
+ if do to.with_c_str |to_buf| {
libc::chmod(to_buf, from_mode as libc::mode_t)
} != 0 {
return false; // should be a condition...
#[cfg(windows)]
fn unlink(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn unlink(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- do p.to_c_str().with_ref |buf| {
+ do p.with_c_str |buf| {
libc::unlink(buf) == (0 as c_int)
}
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn errno_location() -> *c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __error() -> *c_int;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn errno_location() -> *c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __errno_location() -> *c_int;
#[cfg(windows)]
/// Returns the platform-specific value of errno
pub fn errno() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
#[link_name = "kernel32"]
#[cfg(target_os = "freebsd")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
-> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[nolink]
extern {
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
// So we just use __xpg_strerror_r which is always POSIX compliant
#[cfg(target_os = "linux")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __xpg_strerror_r(errnum: c_int,
#[cfg(windows)]
fn strerror() -> ~str {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::DWORD;
use libc::types::os::arch::extra::LPSTR;
use libc::types::os::arch::extra::LPVOID;
*/
#[cfg(target_os = "macos")]
pub fn real_args() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let (argc, argv) = (*_NSGetArgc() as c_int,
*_NSGetArgv() as **c_char);
#[cfg(windows)]
pub fn real_args() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
let mut nArgs: c_int = 0;
let lpArgCount: *mut c_int = &mut nArgs;
let lpCmdLine = unsafe { GetCommandLineW() };
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn glob(pattern: &str) -> ~[Path] {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn default_glob_t () -> libc::glob_t {
}
let mut g = default_glob_t();
- do pattern.to_c_str().with_ref |c_pattern| {
+ do pattern.with_c_str |c_pattern| {
unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) }
};
do(|| {
#[cfg(unix)]
pub fn page_size() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::sysconf(libc::_SC_PAGESIZE) as uint
}
#[cfg(windows)]
pub fn page_size() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut info = libc::SYSTEM_INFO::new();
libc::GetSystemInfo(&mut info);
#[cfg(unix)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::off_t;
let mut addr: *c_void = ptr::null();
#[cfg(unix)]
impl Drop for MemoryMap {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
match libc::munmap(self.data as *c_void, self.len) {
0 => (),
#[cfg(windows)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
let mut lpAddress: LPVOID = ptr::mut_null();
#[cfg(windows)]
impl Drop for MemoryMap {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::{LPCVOID, HANDLE};
unsafe {
#[test]
fn copy_file_ok() {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let tempdir = getcwd(); // would like to use $TMPDIR,
// doesn't seem to work on Linux
let out = tempdir.push("out.txt");
/* Write the temp input file */
- let ostream = do input.to_c_str().with_ref |fromp| {
- do "w+b".to_c_str().with_ref |modebuf| {
+ let ostream = do input.with_c_str |fromp| {
+ do "w+b".with_c_str |modebuf| {
libc::fopen(fromp, modebuf)
}
};
assert!((ostream as uint != 0u));
let s = ~"hello";
- do "hello".to_c_str().with_ref |buf| {
+ do "hello".with_c_str |buf| {
let write_len = libc::fwrite(buf as *c_void,
1u as size_t,
(s.len() + 1u) as size_t,
#[test]
fn memory_map_file() {
+ #[fixed_stack_segment]; #[inline(never)];
+
use result::{Ok, Err};
use os::*;
use libc::*;
#[cfg(unix)]
+ #[fixed_stack_segment]
+ #[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
}
}
#[cfg(windows)]
+ #[fixed_stack_segment]
+ #[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
remove_file(&path);
let fd = unsafe {
- let fd = do path.to_c_str().with_ref |path| {
+ let fd = do path.with_c_str |path| {
open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
};
lseek_(fd, size);
- do "x".to_c_str().with_ref |x| {
+ do "x".with_c_str |x| {
assert!(write(fd, x as *c_void, 1) == 1);
}
fd
#[cfg(target_os = "win32")]
impl WindowsPath {
pub fn stat(&self) -> Option<libc::stat> {
- do self.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf, &mut st) } {
0 => Some(st),
#[cfg(not(target_os = "win32"))]
impl PosixPath {
pub fn stat(&self) -> Option<libc::stat> {
- do self.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf as *libc::c_char, &mut st) } {
0 => Some(st),
#[cfg(unix)]
impl PosixPath {
pub fn lstat(&self) -> Option<libc::stat> {
- do self.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::lstat(buf, &mut st) } {
0 => Some(st),
fn to_c_str(&self) -> c_str::CString {
self.to_str().to_c_str()
}
+
+ unsafe fn to_c_str_unchecked(&self) -> c_str::CString {
+ self.to_str().to_c_str_unchecked()
+ }
}
// FIXME (#3227): when default methods in traits are working, de-duplicate
fn to_c_str(&self) -> c_str::CString {
self.to_str().to_c_str()
}
+
+ unsafe fn to_c_str_unchecked(&self) -> c_str::CString {
+ self.to_str().to_c_str_unchecked()
+ }
}
impl GenericPath for WindowsPath {
}
pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
if (s.len() > 1 &&
libc::isalpha(s[0] as libc::c_int) != 0 &&
pub use from_str::FromStr;
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
-pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
+pub use tuple::{CopyableTuple, ImmutableTuple};
pub use tuple::{CloneableTuple1, ImmutableTuple1};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
}
impl<T> Clone for *T {
+ #[inline]
fn clone(&self) -> *T {
*self
}
passing to the provided callback function
SAFETY NOTE: This will only work with a null-terminated
- pointer array. Barely less-dodgey Pointer Arithmetic.
+ pointer array. Barely less-dodgy Pointer Arithmetic.
Dragons be here.
*/
pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) {
fn test_position() {
use libc::c_char;
- do "hello".to_c_str().with_ref |p| {
+ do "hello".with_c_str |p| {
unsafe {
assert!(2u == position(p, |c| *c == 'l' as c_char));
assert!(4u == position(p, |c| *c == 'o' as c_char));
#[test]
fn test_buf_len() {
- do "hello".to_c_str().with_ref |p0| {
- do "there".to_c_str().with_ref |p1| {
- do "thing".to_c_str().with_ref |p2| {
+ do "hello".with_c_str |p0| {
+ do "there".with_c_str |p1| {
+ do "thing".with_c_str |p2| {
let v = ~[p0, p1, p2, null()];
do v.as_imm_buf |vp, len| {
assert_eq!(unsafe { buf_len(vp) }, 3u);
one, two, three
];
- do arr.as_imm_buf |arr_ptr, arr_len| {
+ do arr.as_imm_buf |arr_ptr, _| {
let mut ctr = 0;
let mut iteration_count = 0;
do array_each(arr_ptr) |e| {
* ~~~
*/
fn shuffle_mut<T>(&mut self, values: &mut [T]);
+
+ /**
+ * Sample up to `n` values from an iterator.
+ *
+ * # Example
+ *
+ * ~~~ {.rust}
+ *
+ * use std::rand;
+ * use std::rand::RngUtil;
+ *
+ * fn main() {
+ * let mut rng = rand::rng();
+ * let vals = range(1, 100).to_owned_vec();
+ * let sample = rng.sample(vals.iter(), 5);
+ * printfln!(sample);
+ * }
+ * ~~~
+ */
+ fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A];
}
/// Extension methods for random number generators
values.swap(i, self.gen_uint_range(0u, i + 1u));
}
}
+
+ /// Randomly sample up to `n` elements from an iterator
+ fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A] {
+ let mut reservoir : ~[A] = vec::with_capacity(n);
+ for (i, elem) in iter.enumerate() {
+ if i < n {
+ reservoir.push(elem);
+ loop
+ }
+
+ let k = self.gen_uint_range(0, i + 1);
+ if k < reservoir.len() {
+ reservoir[k] = elem
+ }
+ }
+ reservoir
+ }
}
/// Create a random number generator with a default algorithm and seed.
/// Create a weak random number generator with a default algorithm and seed.
///
-/// It returns the fatest `Rng` algorithm currently available in Rust without
+/// It returns the fastest `Rng` algorithm currently available in Rust without
/// consideration for cryptography or security. If you require a specifically
/// seeded `Rng` for consistency over time you should pick one algorithm and
/// create the `Rng` yourself.
}
impl XorShiftRng {
- /// Create an xor shift random number generator with a default seed.
+ /// Create an xor shift random number generator with a random seed.
pub fn new() -> XorShiftRng {
- // constants taken from http://en.wikipedia.org/wiki/Xorshift
- XorShiftRng::new_seeded(123456789u32,
- 362436069u32,
- 521288629u32,
- 88675123u32)
+ #[fixed_stack_segment]; #[inline(never)];
+
+ // generate seeds the same way as seed(), except we have a spceific size
+ let mut s = [0u8, ..16];
+ loop {
+ do s.as_mut_buf |p, sz| {
+ unsafe {
+ rustrt::rand_gen_seed(p, sz as size_t);
+ }
+ }
+ if !s.iter().all(|x| *x == 0) {
+ break;
+ }
+ }
+ let s: &[u32, ..4] = unsafe { cast::transmute(&s) };
+ XorShiftRng::new_seeded(s[0], s[1], s[2], s[3])
}
/**
/// Create a new random seed.
pub fn seed() -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let n = rustrt::rand_seed_size() as uint;
let mut s = vec::from_elem(n, 0_u8);
#[cfg(test)]
mod test {
+ use iterator::{Iterator, range};
use option::{Option, Some};
use super::*;
#[test]
fn compare_isaac_implementation() {
+ #[fixed_stack_segment]; #[inline(never)];
+
// This is to verify that the implementation of the ISAAC rng is
// correct (i.e. matches the output of the upstream implementation,
// which is in the runtime)
}
}
}
+
+ #[test]
+ fn test_sample() {
+ let MIN_VAL = 1;
+ let MAX_VAL = 100;
+
+ let mut r = rng();
+ let vals = range(MIN_VAL, MAX_VAL).to_owned_vec();
+ let small_sample = r.sample(vals.iter(), 5);
+ let large_sample = r.sample(vals.iter(), vals.len() + 5);
+
+ assert_eq!(small_sample.len(), 5);
+ assert_eq!(large_sample.len(), vals.len());
+
+ assert!(small_sample.iter().all(|e| {
+ **e >= MIN_VAL && **e <= MAX_VAL
+ }));
+ }
}
#[cfg(test)]
/// # Example
///
/// ~~~
-/// use core::rand::distributions::StandardNormal;
+/// use std::rand::distributions::StandardNormal;
///
/// fn main() {
/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
/// # Example
///
/// ~~~
-/// use core::rand::distributions::Exp1;
+/// use std::rand::distributions::Exp1;
///
/// fn main() {
/// let exp2 = (*rand::random::<Exp1>()) * 0.5;
use iterator::Iterator;
use option::{None, Option, Some, OptionIterator};
use vec;
-use vec::{OwnedVector, ImmutableVector};
-use container::Container;
+use vec::OwnedVector;
use to_str::ToStr;
use str::StrSlice;
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
///
-/// In order to provide informative error messages, `E` is reqired to implement `ToStr`.
+/// In order to provide informative error messages, `E` is required to implement `ToStr`.
/// It is further recommended for `E` to be a descriptive error type, eg a `enum` for
/// all possible errors cases.
#[deriving(Clone, Eq)]
}
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Maps each element in the vector `ts` using the operation `op`. Should an
-/// error occur, no further mappings are performed and the error is returned.
-/// Should no error occur, a vector containing the result of each map is
-/// returned.
+/// Takes each element in the iterator: if it is an error, no further
+/// elements are taken, and the error is returned.
+/// Should no error occur, a vector containing the values of each Result
+/// is returned.
///
/// Here is an example which increments every integer in a vector,
/// checking for overflow:
///
-/// fn inc_conditionally(x: uint) -> result<uint,str> {
+/// fn inc_conditionally(x: uint) -> Result<uint, &'static str> {
/// if x == uint::max_value { return Err("overflow"); }
/// else { return Ok(x+1u); }
/// }
-/// map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
-/// assert!(incd == ~[2u, 3u, 4u]);
-/// }
+/// let v = [1u, 2, 3];
+/// let res = collect(v.iter().map(|&x| inc_conditionally(x)));
+/// assert!(res == Ok(~[2u, 3, 4]));
#[inline]
-pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>)
- -> Result<~[V],U> {
- let mut vs: ~[V] = vec::with_capacity(ts.len());
- for t in ts.iter() {
- match op(t) {
- Ok(v) => vs.push(v),
- Err(u) => return Err(u)
+pub fn collect<T, E, Iter: Iterator<Result<T, E>>>(mut iterator: Iter)
+ -> Result<~[T], E> {
+ let (lower, _) = iterator.size_hint();
+ let mut vs: ~[T] = vec::with_capacity(lower);
+ for t in iterator {
+ match t {
+ Ok(v) => vs.push(v),
+ Err(u) => return Err(u)
}
}
- return Ok(vs);
+ Ok(vs)
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Same as map, but it operates over two parallel vectors.
+/// Perform a fold operation over the result values from an iterator.
///
-/// A precondition is used here to ensure that the vectors are the same
-/// length. While we do not often use preconditions in the standard
-/// library, a precondition is used here because result::t is generally
-/// used in 'careful' code contexts where it is both appropriate and easy
-/// to accommodate an error like the vectors being of different lengths.
+/// If an `Err` is encountered, it is immediately returned.
+/// Otherwise, the folded value is returned.
#[inline]
-pub fn map_vec2<S, T, U: ToStr, V>(ss: &[S], ts: &[T],
- op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> {
- assert!(vec::same_length(ss, ts));
- let n = ts.len();
- let mut vs = vec::with_capacity(n);
- let mut i = 0u;
- while i < n {
- match op(&ss[i],&ts[i]) {
- Ok(v) => vs.push(v),
- Err(u) => return Err(u)
+pub fn fold<T, V, E,
+ Iter: Iterator<Result<T, E>>>(
+ mut iterator: Iter,
+ mut init: V,
+ f: &fn(V, T) -> V)
+ -> Result<V, E> {
+ for t in iterator {
+ match t {
+ Ok(v) => init = f(init, v),
+ Err(u) => return Err(u)
}
- i += 1u;
}
- return Ok(vs);
+ Ok(init)
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Applies op to the pairwise elements from `ss` and `ts`, aborting on
-/// error. This could be implemented using `map_zip()` but it is more efficient
-/// on its own as no result vector is built.
+/// Perform a trivial fold operation over the result values
+/// from an iterator.
+///
+/// If an `Err` is encountered, it is immediately returned.
+/// Otherwise, a simple `Ok(())` is returned.
#[inline]
-pub fn iter_vec2<S, T, U: ToStr>(ss: &[S], ts: &[T],
- op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> {
- assert!(vec::same_length(ss, ts));
- let n = ts.len();
- let mut i = 0u;
- while i < n {
- match op(&ss[i],&ts[i]) {
- Ok(()) => (),
- Err(u) => return Err(u)
- }
- i += 1u;
- }
- return Ok(());
+pub fn fold_<T, E, Iter: Iterator<Result<T, E>>>(
+ iterator: Iter)
+ -> Result<(), E> {
+ fold(iterator, (), |_, _| ())
}
+
#[cfg(test)]
mod tests {
use super::*;
use either;
+ use iterator::range;
use str::OwnedStr;
+ use vec::ImmutableVector;
pub fn op1() -> Result<int, ~str> { Ok(666) }
assert_eq!(r.to_either(), either::Right(100));
assert_eq!(err.to_either(), either::Left(404));
}
+
+ #[test]
+ fn test_collect() {
+ assert_eq!(collect(range(0, 0)
+ .map(|_| Ok::<int, ()>(0))),
+ Ok(~[]));
+ assert_eq!(collect(range(0, 3)
+ .map(|x| Ok::<int, ()>(x))),
+ Ok(~[0, 1, 2]));
+ assert_eq!(collect(range(0, 3)
+ .map(|x| if x > 1 { Err(x) } else { Ok(x) })),
+ Err(2));
+
+ // test that it does not take more elements than it needs
+ let functions = [|| Ok(()), || Err(1), || fail!()];
+
+ assert_eq!(collect(functions.iter().map(|f| (*f)())),
+ Err(1));
+ }
+
+ #[test]
+ fn test_fold() {
+ assert_eq!(fold_(range(0, 0)
+ .map(|_| Ok::<(), ()>(()))),
+ Ok(()));
+ assert_eq!(fold(range(0, 3)
+ .map(|x| Ok::<int, ()>(x)),
+ 0, |a, b| a + b),
+ Ok(3));
+ assert_eq!(fold_(range(0, 3)
+ .map(|x| if x > 1 { Err(x) } else { Ok(()) })),
+ Err(2));
+
+ // test that it does not take more elements than it needs
+ let functions = [|| Ok(()), || Err(1), || fail!()];
+
+ assert_eq!(fold_(functions.iter()
+ .map(|f| (*f)())),
+ Err(1));
+ }
}
args
}
- extern {
- fn rust_take_global_args_lock();
- fn rust_drop_global_args_lock();
- fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>;
+ #[cfg(stage0)]
+ mod macro_hack {
+ #[macro_escape];
+ macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ )
+ )
}
+ externfn!(fn rust_take_global_args_lock())
+ externfn!(fn rust_drop_global_args_lock())
+ externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
+
#[cfg(test)]
mod tests {
use option::{Some, None};
match try_take_task_borrow_list() {
None => { // not recording borrows
let msg = "borrowed";
- do msg.to_c_str().with_ref |msg_p| {
+ do msg.with_c_str |msg_p| {
sys::begin_unwind_(msg_p, file, line);
}
}
sep = " and at ";
}
}
- do msg.to_c_str().with_ref |msg_p| {
+ do msg.with_c_str |msg_p| {
sys::begin_unwind_(msg_p, file, line)
}
}
}
unsafe fn write_cstr(&self, p: *c_char) {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::strlen;
use vec;
let br = borrow_list.pop();
if br.box != a || br.file != file || br.line != line {
let err = fmt!("wrong borrow found, br=%?", br);
- do err.to_c_str().with_ref |msg_p| {
+ do err.with_c_str |msg_p| {
sys::begin_unwind_(msg_p, file, line)
}
}
}
/// A wrapper around libc::malloc, aborting on out-of-memory
-#[inline]
pub unsafe fn malloc_raw(size: uint) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
let p = malloc(size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
}
/// A wrapper around libc::realloc, aborting on out-of-memory
-#[inline]
pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
let p = realloc(ptr, size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
exchange_free(ptr)
}
-#[inline]
pub unsafe fn exchange_free(ptr: *c_char) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(ptr as *c_void);
}
/// (8 bytes).
fn write_le_f64(&mut self, f: f64);
- /// Write a litten-endian IEEE754 single-precision floating-point
+ /// Write a little-endian IEEE754 single-precision floating-point
/// (4 bytes).
fn write_le_f32(&mut self, f: f32);
Readers and Writers may be composed to add capabilities like string
parsing, encoding, and compression.
-This will likely live in core::io, not core::rt::io.
+This will likely live in std::io, not std::rt::io.
# Examples
(continuation-passing) style popularised by node.js. Such systems rely
on all computations being run inside an event loop which maintains a
list of all pending I/O events; when one completes the registered
-callback is run and the code that made the I/O request continiues.
+callback is run and the code that made the I/O request continues.
Such interfaces achieve non-blocking at the expense of being more
difficult to reason about.
while still providing feedback about errors. The basic strategy:
* Errors are fatal by default, resulting in task failure
-* Errors raise the `io_error` conditon which provides an opportunity to inspect
+* Errors raise the `io_error` condition which provides an opportunity to inspect
an IoError object containing details.
* Return values must have a sensible null or zero value which is returned
if a condition is handled successfully. This may be an `Option`, an empty
* XXX: How should we use condition handlers that return values?
* XXX: Should EOF raise default conditions when EOF is not an error?
-# Issues withi/o scheduler affinity, work stealing, task pinning
+# Issues with i/o scheduler affinity, work stealing, task pinning
# Resource management
/// println(reader.read_line());
/// }
///
- /// # Failue
+ /// # Failure
///
/// Returns `true` on failure.
fn eof(&mut self) -> bool;
on_exit: Option<~fn(bool)>,
// nesting level counter for task::unkillable calls (0 == killable).
unkillable: int,
- // nesting level counter for unstable::atomically calls (0 == can yield).
+ // nesting level counter for unstable::atomically calls (0 == can deschedule).
wont_sleep: int,
// A "spare" handle to the kill flag inside the kill handle. Used during
// blocking/waking as an optimization to avoid two xadds on the refcount.
}
/// Enter a possibly-nested "atomic" section of code. Just for assertions.
- /// All calls must be paired with a subsequent call to allow_yield.
+ /// All calls must be paired with a subsequent call to allow_deschedule.
#[inline]
- pub fn inhibit_yield(&mut self) {
+ pub fn inhibit_deschedule(&mut self) {
self.wont_sleep += 1;
}
/// Exit a possibly-nested "atomic" section of code. Just for assertions.
- /// All calls must be paired with a preceding call to inhibit_yield.
+ /// All calls must be paired with a preceding call to inhibit_deschedule.
#[inline]
- pub fn allow_yield(&mut self) {
+ pub fn allow_deschedule(&mut self) {
rtassert!(self.wont_sleep != 0);
self.wont_sleep -= 1;
}
}
impl LocalHeap {
+ #[fixed_stack_segment] #[inline(never)]
pub fn new() -> LocalHeap {
unsafe {
// Don't need synchronization for the single-threaded local heap
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_malloc(self.boxed_region, td, size as size_t);
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn realloc(&mut self, ptr: *OpaqueBox, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_realloc(self.boxed_region, ptr, size as size_t);
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn free(&mut self, box: *OpaqueBox) {
unsafe {
return rust_boxed_region_free(self.boxed_region, box);
}
impl Drop for LocalHeap {
+ #[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
rust_delete_boxed_region(self.boxed_region);
use tls = rt::thread_local_storage;
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
+#[fixed_stack_segment]
+#[inline(never)]
pub fn init_tls_key() {
unsafe {
rust_initialize_rt_tls_key();
}
}
+#[fixed_stack_segment]
+#[inline(never)]
fn maybe_tls_key() -> Option<tls::Key> {
unsafe {
let key: *mut c_void = rust_get_rt_tls_key();
}
extern {
- #[fast_ffi]
fn rust_get_rt_tls_key() -> *mut c_void;
}
-
}
/// Configure logging by traversing the crate map and setting the
/// per-module global logging flags based on the logging spec
+#[fixed_stack_segment] #[inline(never)]
pub fn init(crate_map: *u8) {
use c_str::ToCStr;
use os;
let log_spec = os::getenv("RUST_LOG");
match log_spec {
Some(spec) => {
- do spec.to_c_str().with_ref |buf| {
+ do spec.with_c_str |buf| {
unsafe { rust_update_log_settings(crate_map, buf) }
}
}
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn console_on() { unsafe { rust_log_console_on() } }
+
+#[fixed_stack_segment] #[inline(never)]
pub fn console_off() { unsafe { rust_log_console_off() } }
+
+#[fixed_stack_segment] #[inline(never)]
fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }
extern {
Several modules in `core` are clients of `rt`:
-* `core::task` - The user-facing interface to the Rust task model.
-* `core::task::local_data` - The interface to local data.
-* `core::gc` - The garbage collector.
-* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
-* `core::condition` - Uses local data.
-* `core::cleanup` - Local heap destruction.
-* `core::io` - In the future `core::io` will use an `rt` implementation.
-* `core::logging`
-* `core::pipes`
-* `core::comm`
-* `core::stackwalk`
+* `std::task` - The user-facing interface to the Rust task model.
+* `std::task::local_data` - The interface to local data.
+* `std::gc` - The garbage collector.
+* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`.
+* `std::condition` - Uses local data.
+* `std::cleanup` - Local heap destruction.
+* `std::io` - In the future `std::io` will use an `rt` implementation.
+* `std::logging`
+* `std::pipes`
+* `std::comm`
+* `std::stackwalk`
*/
/// scheduler and task context
pub mod tube;
-/// Simple reimplementation of core::comm
+/// Simple reimplementation of std::comm
pub mod comm;
mod select;
return exit_code;
}
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+)
+}
+
/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
rust_update_gc_metadata(crate_map);
}
- extern {
- fn rust_update_gc_metadata(crate_map: *u8);
- }
+ externfn!(fn rust_update_gc_metadata(crate_map: *u8));
}
/// One-time runtime cleanup.
impl StackSegment {
pub fn new(size: uint) -> StackSegment {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
// Crate a block of uninitialized values
let mut stack = vec::with_capacity(size);
impl Drop for StackSegment {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
// XXX: Using the FFI to call a C macro. Slow
rust_valgrind_stack_deregister(self.valgrind_id);
saved_context: Context
}
-/// Some tasks have a deciated home scheduler that they must run on.
+/// Some tasks have a dedicated home scheduler that they must run on.
pub enum SchedHome {
AnySched,
Sched(SchedHandle)
}
pub fn begin_unwind(&mut self) -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
self.unwinding = true;
unsafe {
rust_begin_unwind(UNWIND_TOKEN);
}
}
}
-
static RLIMIT_NOFILE: libc::c_int = 8;
pub unsafe fn raise_fd_limit() {
+ #[fixed_stack_segment]; #[inline(never)];
+
// The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
// sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
use ptr::{to_unsafe_ptr, to_mut_unsafe_ptr, mut_null};
}
/// Get a port number, starting at 9600, for use in tests
+#[fixed_stack_segment] #[inline(never)]
pub fn next_test_port() -> u16 {
unsafe {
return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;
impl Thread {
pub fn start(main: ~fn()) -> Thread {
fn substart(main: &~fn()) -> *raw_thread {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe { rust_raw_thread_start(main) }
}
let raw = substart(&main);
}
pub fn join(self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(!self.joined);
let mut this = self;
unsafe { rust_raw_thread_join(this.raw_thread); }
impl Drop for Thread {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(self.joined);
unsafe { rust_raw_thread_delete(self.raw_thread) }
}
pub type Key = pthread_key_t;
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn create(key: &mut Key) {
assert_eq!(0, pthread_key_create(key, null()));
}
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert_eq!(0, pthread_setspecific(key, value));
}
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
pthread_getspecific(key)
}
pub type Key = DWORD;
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn create(key: &mut Key) {
static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
*key = TlsAlloc();
}
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert!(0 != TlsSetValue(key, value))
}
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
TlsGetValue(key)
}
/// Get the number of cores available
pub fn num_cpus() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return rust_get_num_cpus();
}
rterrln!("%s", "");
rterrln!("fatal runtime error: %s", msg);
- unsafe { libc::abort(); }
+ abort();
+
+ fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::abort() }
+ }
}
pub fn set_exit_status(code: int) {
-
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_set_exit_status_newrt(code as libc::uintptr_t);
}
}
pub fn get_exit_status() -> int {
-
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_get_exit_status_newrt() as int;
}
/*!
-Bindings to libuv, along with the default implementation of `core::rt::rtio`.
+Bindings to libuv, along with the default implementation of `std::rt::rtio`.
UV types consist of the event loop (Loop), Watchers, Requests and
Callbacks.
/// Transmute an owned vector to a Buf
pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let data = malloc(v.len() as size_t) as *u8;
assert!(data.is_not_null());
/// Transmute a Buf that was once a ~[u8] back to ~[u8]
pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
+ #[fixed_stack_segment]; #[inline(never)];
+
if !(buf.len == 0 && buf.base.is_null()) {
let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
unsafe { free(buf.base as *c_void) };
fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
handle: U) -> Result<SocketAddr, IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
let getsockname = match sk {
TcpPeer => uvll::rust_uv_tcp_getpeername,
}
fn accept_simultaneously(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 1 as c_int)
};
}
fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 0 as c_int)
};
}
fn control_congestion(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_nodelay(self.native_handle(), 0 as c_int)
};
}
fn nodelay(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_nodelay(self.native_handle(), 1 as c_int)
};
}
fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_keepalive(self.native_handle(), 1 as c_int,
delay_in_seconds as c_uint)
}
fn letdie(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_keepalive(self.native_handle(), 0 as c_int, 0 as c_uint)
};
fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
let r = unsafe {
- do multi.to_str().to_c_str().with_ref |m_addr| {
+ do multi.to_str().with_c_str |m_addr| {
uvll::udp_set_membership(self.native_handle(), m_addr,
ptr::null(), uvll::UV_JOIN_GROUP)
}
fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
let r = unsafe {
- do multi.to_str().to_c_str().with_ref |m_addr| {
+ do multi.to_str().with_c_str |m_addr| {
uvll::udp_set_membership(self.native_handle(), m_addr,
ptr::null(), uvll::UV_LEAVE_GROUP)
}
* There are also a collection of helper functions to ease interacting
* with the low-level API.
*
- * As new functionality, existant in uv.h, is added to the rust stdlib,
+ * As new functionality, existent in uv.h, is added to the rust stdlib,
* the mappings should be added in this module.
*/
}
pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX);
let size = rust_uv_handle_size(handle as uint);
let p = malloc(size);
}
pub unsafe fn free_handle(v: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(v)
}
pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX);
let size = rust_uv_req_size(req as uint);
let p = malloc(size);
}
pub unsafe fn free_req(v: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(v)
}
#[test]
fn handle_sanity_check() {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max());
}
}
#[test]
+#[fixed_stack_segment]
+#[inline(never)]
fn request_sanity_check() {
unsafe {
assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
}
pub unsafe fn loop_new() -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_loop_new();
}
pub unsafe fn loop_delete(loop_handle: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_loop_delete(loop_handle);
}
pub unsafe fn run(loop_handle: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_run(loop_handle);
}
pub unsafe fn close<T>(handle: *T, cb: *u8) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_close(handle as *c_void, cb);
}
pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_walk(loop_handle, cb, arg);
}
pub unsafe fn idle_new() -> *uv_idle_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_new()
}
pub unsafe fn idle_delete(handle: *uv_idle_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_delete(handle)
}
pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_init(loop_handle, handle)
}
pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_start(handle, cb)
}
pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_stop(handle)
}
pub unsafe fn udp_init(loop_handle: *uv_loop_t, handle: *uv_udp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_init(loop_handle, handle);
}
pub unsafe fn udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_bind(server, addr, flags);
}
pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_bind6(server, addr, flags);
}
pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb,
on_recv: uv_udp_recv_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_recv_start(server, on_alloc, on_recv);
}
pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_recv_stop(server);
}
pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_udp_handle_from_send_req(send_req);
}
pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_getsockname(handle, name);
}
pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char,
interface_addr: *c_char, membership: uv_membership) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership as c_int);
}
pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_multicast_loop(handle, on);
}
pub unsafe fn udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_multicast_ttl(handle, ttl);
}
pub unsafe fn udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_ttl(handle, ttl);
}
pub unsafe fn udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_broadcast(handle, on);
}
pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_init(loop_handle, handle);
}
pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
}
pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_getsockname(handle, name);
}
pub unsafe fn tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_nodelay(handle, enable);
}
pub unsafe fn tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_keepalive(handle, enable, delay);
}
pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_simultaneous_accepts(handle, enable);
}
pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_listen(stream as *c_void, backlog, cb);
}
pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_accept(server as *c_void, client as *c_void);
}
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
}
pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: uv_alloc_cb, on_read: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_read_start(stream as *c_void, on_alloc, on_read);
}
pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_read_stop(stream as *c_void);
}
pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_last_error(loop_handle);
}
pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_strerror(err);
}
pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_err_name(err);
}
pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_async_init(loop_handle, async_handle, cb);
}
pub unsafe fn async_send(async_handle: *uv_async_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_async_send(async_handle);
}
pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t };
let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf);
rust_uv_buf_init(out_buf_ptr, input, len as size_t);
}
pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_init(loop_ptr, timer_ptr);
}
pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64,
repeat: u64) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_start(timer_ptr, cb, timeout, repeat);
}
pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_stop(timer_ptr);
}
pub unsafe fn is_ip4_addr(addr: *sockaddr) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
match rust_uv_is_ipv4_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
match rust_uv_is_ipv6_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in {
- do ip.to_c_str().with_ref |ip_buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do ip.with_c_str |ip_buf| {
rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 {
- do ip.to_c_str().with_ref |ip_buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do ip.with_c_str |ip_buf| {
rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_sockaddr_storage() -> *sockaddr_storage {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_malloc_sockaddr_storage()
}
pub unsafe fn free_sockaddr_storage(ss: *sockaddr_storage) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_sockaddr_storage(ss);
}
pub unsafe fn free_ip4_addr(addr: *sockaddr_in) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_ip4_addr(addr);
}
pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_ip6_addr(addr);
}
pub unsafe fn ip4_name(addr: *sockaddr_in, dst: *u8, size: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip4_name(addr, dst, size);
}
pub unsafe fn ip6_name(addr: *sockaddr_in6, dst: *u8, size: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip6_name(addr, dst, size);
}
pub unsafe fn ip4_port(addr: *sockaddr_in) -> c_uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip4_port(addr);
}
pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip6_port(addr);
}
// data access helpers
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_loop_for_uv_handle(handle as *c_void);
}
pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_stream_handle_from_connect_req(connect);
}
pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_stream_handle_from_write_req(write_req);
}
pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_get_data_for_uv_loop(loop_ptr)
}
pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_uv_loop(loop_ptr, data);
}
pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_data_for_uv_handle(handle as *c_void);
}
pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void);
}
pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_data_for_req(req as *c_void);
}
pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_req(req as *c_void, data as *c_void);
}
pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_base_from_buf(buf);
}
pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_len_from_buf(buf);
}
pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
* If this is Some(vec-of-names-and-values) then the new process will
* have an environment containing the given named values only.
*/
- env: Option<&'self [(~str, ~str)]>,
+ env: Option<~[(~str, ~str)]>,
/**
* If this is None then the new process will use the same initial working
in_fd: Option<c_int>,
/**
- * If this is None then a new pipe will be created for the new progam's
+ * If this is None then a new pipe will be created for the new program's
* output and Process.output() will provide a Reader to read from this pipe.
*
* If this is Some(file-descriptor) then the new process will write its output
out_fd: Option<c_int>,
/**
- * If this is None then a new pipe will be created for the new progam's
+ * If this is None then a new pipe will be created for the new program's
* error stream and Process.error() will provide a Reader to read from this pipe.
*
* If this is Some(file-descriptor) then the new process will write its error output
* * options - Options to configure the environment of the process,
* the working directory and the standard IO streams.
*/
- pub fn new(prog: &str, args: &[~str], options: ProcessOptions)
+ pub fn new(prog: &str, args: &[~str],
+ options: ProcessOptions)
-> Process {
+ #[fixed_stack_segment]; #[inline(never)];
+
let (in_pipe, in_fd) = match options.in_fd {
None => {
let pipe = os::pipe();
Some(fd) => (None, fd)
};
- let res = spawn_process_os(prog, args, options.env, options.dir,
+ let res = spawn_process_os(prog, args, options.env.clone(), options.dir,
in_fd, out_fd, err_fd);
unsafe {
* method does nothing.
*/
pub fn close_input(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
match self.input {
Some(-1) | None => (),
Some(fd) => {
}
fn close_outputs(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
fclose_and_null(&mut self.output);
fclose_and_null(&mut self.error);
fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
+ #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
match *f_opt {
Some(f) if !f.is_null() => {
unsafe {
#[cfg(windows)]
fn killpid(pid: pid_t, _force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::TerminateProcess(
cast::transmute(pid), 1);
#[cfg(unix)]
fn killpid(pid: pid_t, force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
+
let signal = if force {
libc::consts::os::posix88::SIGKILL
} else {
#[cfg(windows)]
fn spawn_process_os(prog: &str, args: &[~str],
- env: Option<&[(~str, ~str)]>,
+ env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
use libc::consts::os::extra::{
do with_envp(env) |envp| {
do with_dirp(dir) |dirp| {
- do cmd.to_c_str().with_ref |cmdp| {
+ do cmd.with_c_str |cmdp| {
let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
ptr::mut_null(), ptr::mut_null(), TRUE,
0, envp, dirp, &mut si, &mut pi);
#[cfg(unix)]
fn spawn_process_os(prog: &str, args: &[~str],
- env: Option<&[(~str, ~str)]>,
+ env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
use libc::funcs::bsd44::getdtablesize;
}
#[cfg(unix)]
-fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
use vec;
// On posixy systems we can pass a char** for envp, which is a
}
#[cfg(windows)]
-fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
// On win32 we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
match d {
- Some(dir) => dir.to_c_str().with_ref(|buf| cb(buf)),
+ Some(dir) => dir.with_c_str(|buf| cb(buf)),
None => cb(ptr::null())
}
}
#[cfg(windows)]
fn free_handle(handle: *()) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
* Note that this is private to avoid race conditions on unix where if
* a user calls waitpid(some_process.get_id()) then some_process.finish()
* and some_process.destroy() and some_process.finalize() will then either
- * operate on a none-existant process or, even worse, on a newer process
+ * operate on a none-existent process or, even worse, on a newer process
* with the same id.
*/
fn waitpid(pid: pid_t) -> int {
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
#[cfg(unix)]
fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix01::wait::*;
}
fn readclose(fd: c_int) -> ~str {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let file = os::fdopen(fd);
let reader = io::FILE_reader(file, false);
}
#[cfg(unix,not(target_os="android"))]
- fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("env", [], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
})
}
#[cfg(unix,target_os="android")]
- fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
}
#[cfg(windows)]
- fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
let mut new_env = os::env();
new_env.push((~"RUN_TEST_NEW_ENV", ~"123"));
- let mut prog = run_env(Some(new_env.slice(0, new_env.len())));
+ let mut prog = run_env(Some(new_env));
let output = str::from_bytes(prog.finish_with_output().output);
assert!(output.contains("RUN_TEST_NEW_ENV=123"));
}
fn running_on_valgrind() -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe { rust_running_on_valgrind() != 0 }
}
use rt::local::Local;
use rt::rtio::EventLoop;
use task;
+use unstable::finally::Finally;
use vec::{OwnedVector, MutableVector};
/// Trait for message-passing primitives that can be select()ed on.
let p = Cell::new(p);
let c = Cell::new(c);
- let sched = Local::take::<Scheduler>();
- do sched.deschedule_running_task_and_then |sched, task| {
- let task_handles = task.make_selectable(ports.len());
-
- for (index, (port, task_handle)) in
- ports.mut_iter().zip(task_handles.move_iter()).enumerate() {
- // If one of the ports has data by now, it will wake the handle.
- if port.block_on(sched, task_handle) {
- ready_index = index;
- break;
+ do (|| {
+ let c = Cell::new(c.take());
+ let sched = Local::take::<Scheduler>();
+ do sched.deschedule_running_task_and_then |sched, task| {
+ let task_handles = task.make_selectable(ports.len());
+
+ for (index, (port, task_handle)) in
+ ports.mut_iter().zip(task_handles.move_iter()).enumerate() {
+ // If one of the ports has data by now, it will wake the handle.
+ if port.block_on(sched, task_handle) {
+ ready_index = index;
+ break;
+ }
}
- }
- let c = Cell::new(c.take());
- do sched.event_loop.callback { c.take().send_deferred(()) }
+ let c = Cell::new(c.take());
+ do sched.event_loop.callback { c.take().send_deferred(()) }
+ }
+ }).finally {
+ let p = Cell::new(p.take());
+ // Unkillable is necessary not because getting killed is dangerous here,
+ // but to force the recv not to use the same kill-flag that we used for
+ // selecting. Otherwise a user-sender could spuriously wakeup us here.
+ do task::unkillable { p.take().recv(); }
}
- // Unkillable is necessary not because getting killed is dangerous here,
- // but to force the recv not to use the same kill-flag that we used for
- // selecting. Otherwise a user-sender could spuriously wakeup us here.
- do task::unkillable { p.take().recv(); }
-
// Task resumes. Now unblock ourselves from all the ports we blocked on.
// If the success index wasn't reset, 'take' will just take all of them.
// Iterate in reverse so the 'earliest' index that's ready gets returned.
let (c2, p3, c4) = x.take();
p3.recv(); // handshake parent
c4.send(()); // normal receive
- task::yield();
+ task::deschedule();
c2.send(()); // select receive
}
if send_on_chans.contains(&i) {
let c = Cell::new(c);
do spawntask_random {
- task::yield();
+ task::deschedule();
c.take().send(());
}
}
pub use fmt;
pub use to_bytes;
}
+
use cast;
use char;
use char::Char;
-use clone::Clone;
+use clone::{Clone, DeepClone};
use container::{Container, Mutable};
use iter::Times;
use iterator::{Iterator, FromIterator, Extendable};
}
}
-/// An iterator over the start and end indicies of the matches of a
+/// An iterator over the start and end indices of the matches of a
/// substring within a larger string
#[deriving(Clone)]
pub struct MatchesIndexIterator<'self> {
/// Sets the length of a string
///
/// This will explicitly set the size of the string, without actually
- /// modifing its buffers, so it is up to the caller to ensure that
+ /// modifying its buffers, so it is up to the caller to ensure that
/// the string is actually the specified size.
#[inline]
pub unsafe fn set_len(s: &mut ~str, new_len: uint) {
}
}
+impl DeepClone for ~str {
+ #[inline]
+ fn deep_clone(&self) -> ~str {
+ self.to_owned()
+ }
+}
+
impl Clone for @str {
#[inline]
fn clone(&self) -> @str {
}
}
-impl<T: Iterator<char>> FromIterator<char, T> for ~str {
+impl DeepClone for @str {
+ #[inline]
+ fn deep_clone(&self) -> @str {
+ *self
+ }
+}
+
+impl FromIterator<char> for ~str {
#[inline]
- fn from_iterator(iterator: &mut T) -> ~str {
+ fn from_iterator<T: Iterator<char>>(iterator: &mut T) -> ~str {
let (lower, _) = iterator.size_hint();
let mut buf = with_capacity(lower);
buf.extend(iterator);
}
}
-impl<T: Iterator<char>> Extendable<char, T> for ~str {
+impl Extendable<char> for ~str {
#[inline]
- fn extend(&mut self, iterator: &mut T) {
+ fn extend<T: Iterator<char>>(&mut self, iterator: &mut T) {
let (lower, _) = iterator.size_hint();
let reserve = lower + self.len();
self.reserve_at_least(reserve);
#[test]
fn test_map() {
+ #[fixed_stack_segment]; #[inline(never)];
assert_eq!(~"", "".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
assert_eq!(~"YMCA", "ymca".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
}
#[cfg(test)]
mod tests {
use super::*;
- use to_bytes::ToBytes;
use str::from_char;
macro_rules! v2ascii (
#[test]
fn test_ascii_to_bytes() {
- assert_eq!(v2ascii!(~[40, 32, 59]).to_bytes(false), ~[40u8, 32u8, 59u8]);
assert_eq!(v2ascii!(~[40, 32, 59]).into_bytes(), ~[40u8, 32u8, 59u8]);
}
impl FailWithCause for ~str {
fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
- do cause.to_c_str().with_ref |msg_buf| {
- do file.to_c_str().with_ref |file_buf| {
+ do cause.with_c_str |msg_buf| {
+ do file.with_c_str |file_buf| {
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
}
}
impl FailWithCause for &'static str {
fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
- do cause.to_c_str().with_ref |msg_buf| {
- do file.to_c_str().with_ref |file_buf| {
+ do cause.with_c_str |msg_buf| {
+ do file.with_c_str |file_buf| {
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
}
}
// above.
let data = match util::replace(entry, None) {
Some((_, data, _)) => data,
- None => libc::abort(),
+ None => abort(),
};
// Move `data` into transmute to get out the memory that it
}
}
}
- _ => libc::abort()
+ _ => abort()
}
// n.b. 'data' and 'loans' are both invalid pointers at the point
if return_loan {
match map[i] {
Some((_, _, ref mut loan)) => { *loan = NoLoan; }
- None => { libc::abort(); }
+ None => { abort(); }
}
}
return ret;
}
}
+fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ unsafe { libc::abort() }
+}
+
pub unsafe fn local_set<T: 'static>(handle: Handle,
key: local_data::Key<T>,
data: T) {
spawn::spawn_raw(opts, f);
}
- /// Runs a task, while transfering ownership of one argument to the child.
+ /// Runs a task, while transferring ownership of one argument to the child.
pub fn spawn_with<A:Send>(&mut self, arg: A, f: ~fn(v: A)) {
let arg = Cell::new(arg);
do self.spawn {
pub fn spawn_with<A:Send>(arg: A, f: ~fn(v: A)) {
/*!
- * Runs a task, while transfering ownership of one argument to the
+ * Runs a task, while transferring ownership of one argument to the
* child.
*
- * This is useful for transfering ownership of noncopyables to
+ * This is useful for transferring ownership of noncopyables to
* another task.
*
* This function is equivalent to `task().spawn_with(arg, f)`.
}
}
-pub fn yield() {
+pub fn deschedule() {
//! Yield control to the task scheduler
use rt::local::Local;
*
* ~~~
* do task::unkillable {
- * // detach / yield / destroy must all be called together
+ * // detach / deschedule / destroy must all be called together
* rustrt::rust_port_detach(po);
* // This must not result in the current task being killed
- * task::yield();
+ * task::deschedule();
* rustrt::rust_port_destroy(po);
* }
* ~~~
let ch = ch.clone();
do spawn_unlinked {
// Give middle task a chance to fail-but-not-kill-us.
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
ch.send(()); // If killed first, grandparent hangs.
}
fail!(); // Shouldn't kill either (grand)parent or (grand)child.
do run_in_newsched_task {
do spawn_supervised { fail!(); }
// Give child a chance to fail-but-not-kill-us.
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
}
}
#[ignore(reason = "linked failure")]
do spawn_supervised {
do spawn_supervised { block_forever(); }
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
do spawn_supervised {
do spawn { block_forever(); } // linked
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
do spawn { // linked
do spawn_supervised { block_forever(); }
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
do spawn { // linked
do spawn { block_forever(); } // linked
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
mod testrt {
use libc;
- #[nolink]
- extern {
- pub fn rust_dbg_lock_create() -> *libc::c_void;
- pub fn rust_dbg_lock_destroy(lock: *libc::c_void);
- pub fn rust_dbg_lock_lock(lock: *libc::c_void);
- pub fn rust_dbg_lock_unlock(lock: *libc::c_void);
- pub fn rust_dbg_lock_wait(lock: *libc::c_void);
- pub fn rust_dbg_lock_signal(lock: *libc::c_void);
- }
+ externfn!(fn rust_dbg_lock_create() -> *libc::c_void)
+ externfn!(fn rust_dbg_lock_destroy(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_lock(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_unlock(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_wait(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_signal(lock: *libc::c_void))
}
#[test]
// We want to do this after failing
do spawn_unlinked {
- do 10.times { yield() }
+ do 10.times { deschedule() }
ch.send(());
}
do spawn {
- yield();
+ deschedule();
// We want to fail after the unkillable task
// blocks on recv
fail!();
// We want to do this after failing
do spawn_unlinked || {
- do 10.times { yield() }
+ do 10.times { deschedule() }
ch.send(());
}
do spawn {
- yield();
+ deschedule();
// We want to fail after the unkillable task
// blocks on recv
fail!();
t.unlinked();
t.watched();
do t.spawn {
- task::yield();
+ task::deschedule();
fail!();
}
}
t.unwatched();
do t.spawn {
p3.recv();
- task::yield();
+ task::deschedule();
fail!();
}
c3.send(());
*/
use cast;
+use container::Container;
use io;
use io::Writer;
use iterator::Iterator;
use option::{None, Option, Some};
-use str::StrSlice;
-use vec::ImmutableVector;
+use str::{Str, StrSlice};
+use vec::{Vector, ImmutableVector};
pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool;
-/**
- * A trait to implement in order to make a type hashable;
- * This works in combination with the trait `Hash::Hash`, and
- * may in the future be merged with that trait or otherwise
- * modified when default methods and trait inheritence are
- * completed.
- */
+///
+/// A trait to implement in order to make a type hashable;
+/// This works in combination with the trait `std::hash::Hash`, and
+/// may in the future be merged with that trait or otherwise
+/// modified when default methods and trait inheritance are
+/// completed.
+///
+/// IterBytes should be implemented so that the extent of the
+/// produced byte stream can be discovered, given the original
+/// type.
+/// For example, the IterBytes implementation for vectors emits
+/// its length first, and enums should emit their discriminant.
+///
pub trait IterBytes {
- /**
- * Call the provided callback `f` one or more times with
- * byte-slices that should be used when computing a hash
- * value or otherwise "flattening" the structure into
- * a sequence of bytes. The `lsb0` parameter conveys
- * whether the caller is asking for little-endian bytes
- * (`true`) or big-endian (`false`); this should only be
- * relevant in implementations that represent a single
- * multi-byte datum such as a 32 bit integer or 64 bit
- * floating-point value. It can be safely ignored for
- * larger structured types as they are usually processed
- * left-to-right in declaration order, regardless of
- * underlying memory endianness.
- */
+ /// Call the provided callback `f` one or more times with
+ /// byte-slices that should be used when computing a hash
+ /// value or otherwise "flattening" the structure into
+ /// a sequence of bytes. The `lsb0` parameter conveys
+ /// whether the caller is asking for little-endian bytes
+ /// (`true`) or big-endian (`false`); this should only be
+ /// relevant in implementations that represent a single
+ /// multi-byte datum such as a 32 bit integer or 64 bit
+ /// floating-point value. It can be safely ignored for
+ /// larger structured types as they are usually processed
+ /// left-to-right in declaration order, regardless of
+ /// underlying memory endianness.
+ ///
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool;
}
impl<'self,A:IterBytes> IterBytes for &'self [A] {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ self.len().iter_bytes(lsb0, |b| f(b)) &&
self.iter().advance(|elt| elt.iter_bytes(lsb0, |b| f(b)))
}
}
-impl<A:IterBytes,B:IterBytes> IterBytes for (A,B) {
- #[inline]
- fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- match *self {
- (ref a, ref b) => { a.iter_bytes(lsb0, |b| f(b)) &&
- b.iter_bytes(lsb0, |b| f(b)) }
- }
- }
-}
-
-impl<A:IterBytes,B:IterBytes,C:IterBytes> IterBytes for (A,B,C) {
- #[inline]
- fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- match *self {
- (ref a, ref b, ref c) => {
- a.iter_bytes(lsb0, |b| f(b)) &&
- b.iter_bytes(lsb0, |b| f(b)) &&
- c.iter_bytes(lsb0, |b| f(b))
- }
+impl<A: IterBytes> IterBytes for (A, ) {
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ match *self {
+ (ref a, ) => a.iter_bytes(lsb0, |b| f(b))
+ }
}
- }
}
-// Move this to vec, probably.
-fn borrow<'x,A>(a: &'x [A]) -> &'x [A] {
- a
-}
+macro_rules! iter_bytes_tuple(
+ ($($A:ident),+) => (
+ impl<$($A: IterBytes),+> IterBytes for ($($A),+) {
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ match *self {
+ ($(ref $A),+) => {
+ $(
+ $A .iter_bytes(lsb0, |b| f(b))
+ )&&+
+ }
+ }
+ }
+ }
+ )
+)
+
+iter_bytes_tuple!(A, B)
+iter_bytes_tuple!(A, B, C)
+iter_bytes_tuple!(A, B, C, D)
+iter_bytes_tuple!(A, B, C, D, E)
+iter_bytes_tuple!(A, B, C, D, E, F)
+iter_bytes_tuple!(A, B, C, D, E, F, G)
+iter_bytes_tuple!(A, B, C, D, E, F, G, H)
impl<A:IterBytes> IterBytes for ~[A] {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- borrow(*self).iter_bytes(lsb0, f)
+ self.as_slice().iter_bytes(lsb0, f)
}
}
impl<A:IterBytes> IterBytes for @[A] {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- borrow(*self).iter_bytes(lsb0, f)
+ self.as_slice().iter_bytes(lsb0, f)
}
}
impl<'self> IterBytes for &'self str {
#[inline]
fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool {
- f(self.as_bytes())
+ // Terminate the string with a byte that does not appear in UTF-8
+ f(self.as_bytes()) && f([0xFF])
}
}
impl IterBytes for ~str {
#[inline]
- fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool {
- // this should possibly include the null terminator, but that
- // breaks .find_equiv on hashmaps.
- f(self.as_bytes())
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ self.as_slice().iter_bytes(lsb0, f)
}
}
impl IterBytes for @str {
#[inline]
- fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool {
- // this should possibly include the null terminator, but that
- // breaks .find_equiv on hashmaps.
- f(self.as_bytes())
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ self.as_slice().iter_bytes(lsb0, f)
}
}
/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
- /// Cosume and convert to a string.
+ /// Consume and convert to a string.
fn into_str(self) -> ~str;
}
}
}
-impl<T, Iter: Iterator<(uint, T)>> FromIterator<(uint, T), Iter> for TrieMap<T> {
- fn from_iterator(iter: &mut Iter) -> TrieMap<T> {
+impl<T> FromIterator<(uint, T)> for TrieMap<T> {
+ fn from_iterator<Iter: Iterator<(uint, T)>>(iter: &mut Iter) -> TrieMap<T> {
let mut map = TrieMap::new();
map.extend(iter);
map
}
}
-impl<T, Iter: Iterator<(uint, T)>> Extendable<(uint, T), Iter> for TrieMap<T> {
- fn extend(&mut self, iter: &mut Iter) {
+impl<T> Extendable<(uint, T)> for TrieMap<T> {
+ fn extend<Iter: Iterator<(uint, T)>>(&mut self, iter: &mut Iter) {
for (k, v) in *iter {
self.insert(k, v);
}
}
}
-impl<Iter: Iterator<uint>> FromIterator<uint, Iter> for TrieSet {
- fn from_iterator(iter: &mut Iter) -> TrieSet {
+impl FromIterator<uint> for TrieSet {
+ fn from_iterator<Iter: Iterator<uint>>(iter: &mut Iter) -> TrieSet {
let mut set = TrieSet::new();
set.extend(iter);
set
}
}
-impl<Iter: Iterator<uint>> Extendable<uint, Iter> for TrieSet {
- fn extend(&mut self, iter: &mut Iter) {
+impl Extendable<uint> for TrieSet {
+ fn extend<Iter: Iterator<uint>>(&mut self, iter: &mut Iter) {
for elem in *iter {
self.insert(elem);
}
#[allow(missing_doc)];
use clone::Clone;
-use vec;
-use vec::ImmutableVector;
-use iterator::Iterator;
pub use self::inner::*;
}
}
-pub trait ExtendedTupleOps<A,B> {
- fn zip(&self) -> ~[(A, B)];
- fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C];
-}
-
-impl<'self,
- A:Clone,
- B:Clone>
- ExtendedTupleOps<A,B> for
- (&'self [A], &'self [B]) {
- #[inline]
- fn zip(&self) -> ~[(A, B)] {
- match *self {
- (ref a, ref b) => {
- vec::zip_slice(*a, *b)
- }
- }
- }
-
- #[inline]
- fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] {
- match *self {
- (ref a, ref b) => {
- a.iter().zip(b.iter()).map(|(aa, bb)| f(aa, bb)).collect()
- }
- }
- }
-}
-
-impl<A:Clone, B:Clone> ExtendedTupleOps<A,B> for (~[A], ~[B]) {
- #[inline]
- fn zip(&self) -> ~[(A, B)] {
- match *self {
- (ref a, ref b) => {
- vec::zip_slice(*a, *b)
- }
- }
- }
-
- #[inline]
- fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] {
- match *self {
- (ref a, ref b) => {
- a.iter().zip(b.iter()).map(|(aa, bb)| f(aa, bb)).collect()
- }
- }
- }
-}
-
// macro for implementing n-ary tuple functions and operations
macro_rules! tuple_impls {
}
/**
- * A signed atomic integer type, supporting basic atomic aritmetic operations
+ * A signed atomic integer type, supporting basic atomic arithmetic operations
*/
pub struct AtomicInt {
priv v: int
}
/**
- * An unsigned atomic integer type, supporting basic atomic aritmetic operations
+ * An unsigned atomic integer type, supporting basic atomic arithmetic operations
*/
pub struct AtomicUint {
priv v: uint
* A fence 'A' which has `Release` ordering semantics, synchronizes with a
* fence 'B' with (at least) `Acquire` semantics, if and only if there exists
* atomic operations X and Y, both operating on some atomic object 'M' such
- * that A is sequenced before X, Y is synchronized before B and Y obsevers
+ * that A is sequenced before X, Y is synchronized before B and Y observers
* the change to M. This provides a happens-before dependence between A and B.
*
* Atomic operations with `Release` or `Acquire` semantics can also synchronize
// T but that feature is still unimplemented
let maybe_symbol_value = do dl::check_for_errors_in {
- do symbol.to_c_str().with_ref |raw_string| {
+ do symbol.with_c_str |raw_string| {
dl::symbol(self.handle, raw_string)
}
};
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
- do filename.to_c_str().with_ref |raw_name| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do filename.with_c_str |raw_name| {
dlopen(raw_name, Lazy as libc::c_int)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlopen(ptr::null(), Lazy as libc::c_int)
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do atomically {
let _old_error = dlerror();
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlsym(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlclose(handle); ()
}
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
do os::win32::as_utf16_p(filename.to_str()) |raw_name| {
LoadLibraryW(raw_name)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
let handle = ptr::null();
GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
handle
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do atomically {
SetLastError(0);
}
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
GetProcAddress(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
FreeLibrary(handle); ()
}
do || {
...
}.finally {
- alway_run_this();
+ always_run_this();
}
~~~
*/
A quick refresher on memory ordering:
-* Acquire - a barrier for aquiring a lock. Subsequent reads and writes
+* Acquire - a barrier for acquiring a lock. Subsequent reads and writes
take place after the barrier.
* Release - a barrier for releasing a lock. Preceding reads and writes
take place before the barrier.
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);
- do msg.to_c_str().with_ref |buf| {
+ do msg.with_c_str |buf| {
fail_(buf, file, line);
}
}
borrowck::check_not_borrowed(a, file, line)
}
-#[lang="annihilate"]
-pub unsafe fn annihilate() {
- ::cleanup::annihilate()
-}
-
#[lang="start"]
pub fn start(main: *u8, argc: int, argv: **c_char,
crate_map: *u8) -> int {
/// can lead to deadlock. Calling change_dir_locked recursively will
/// also deadlock.
pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
use os;
use os::change_dir;
use unstable::sync::atomically;
/**
* Enables a runtime assertion that no operation in the argument closure shall
- * use scheduler operations (yield, recv, spawn, etc). This is for use with
+ * use scheduler operations (deschedule, recv, spawn, etc). This is for use with
* pthread mutexes, which may block the entire scheduler thread, rather than
- * just one task, and is hence prone to deadlocks if mixed with yielding.
+ * just one task, and is hence prone to deadlocks if mixed with descheduling.
*
* NOTE: THIS DOES NOT PROVIDE LOCKING, or any sort of critical-section
* synchronization whatsoever. It only makes sense to use for CPU-local issues.
if in_green_task_context() {
let t = Local::unsafe_borrow::<Task>();
do (|| {
- (*t).death.inhibit_yield();
+ (*t).death.inhibit_deschedule();
f()
}).finally {
- (*t).death.allow_yield();
+ (*t).death.allow_deschedule();
}
} else {
f()
}
}
- #[inline]
pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
do atomically {
rust_lock_little_lock(self.l);
* This uses a pthread mutex, not one that's aware of the userspace scheduler.
* The user of an Exclusive must be careful not to invoke any functions that may
* reschedule the task while holding the lock, or deadlock may result. If you
- * need to block or yield while accessing shared state, use extra::sync::RWArc.
+ * need to block or deschedule while accessing shared state, use extra::sync::RWArc.
*/
pub struct Exclusive<T> {
x: UnsafeAtomicRcBox<ExData<T>>
// Exactly like std::arc::MutexArc,access(), but with the LittleLock
// instead of a proper mutex. Same reason for being unsafe.
//
- // Currently, scheduling operations (i.e., yielding, receiving on a pipe,
+ // Currently, scheduling operations (i.e., descheduling, receiving on a pipe,
// accessing the provided condition variable) are prohibited while inside
// the Exclusive. Supporting that is a work in progress.
#[inline]
}
}
-extern {
- fn rust_create_little_lock() -> rust_little_lock;
- fn rust_destroy_little_lock(lock: rust_little_lock);
- fn rust_lock_little_lock(lock: rust_little_lock);
- fn rust_unlock_little_lock(lock: rust_little_lock);
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ );
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+)
}
+externfn!(fn rust_create_little_lock() -> rust_little_lock)
+externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
+externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
+externfn!(fn rust_unlock_little_lock(lock: rust_little_lock))
+
#[cfg(test)]
mod tests {
use cell::Cell;
fn test_atomically() {
// NB. The whole runtime will abort on an 'atomic-sleep' violation,
// so we can't really test for the converse behaviour.
- unsafe { do atomically { } } task::yield(); // oughtn't fail
+ unsafe { do atomically { } } task::deschedule(); // oughtn't fail
}
#[test]
c.send(());
}
p.recv();
- task::yield(); // Try to make the unwrapper get blocked first.
+ task::deschedule(); // Try to make the unwrapper get blocked first.
let left_x = x.try_unwrap();
assert!(left_x.is_left());
util::ignore(left_x);
do task::spawn {
let x2 = x2.take();
unsafe { do x2.with |_hello| { } }
- task::yield();
+ task::deschedule();
}
assert!(x.unwrap() == ~~"hello");
let x = Exclusive::new(~~"hello");
let x2 = x.clone();
do task::spawn {
- do 10.times { task::yield(); } // try to let the unwrapper go
+ do 10.times { task::deschedule(); } // try to let the unwrapper go
fail!(); // punt it awake from its deadlock
}
let _z = x.unwrap();
(ts, us)
}
-/**
- * Convert two vectors to a vector of pairs, by reference. As zip().
- */
-pub fn zip_slice<T:Clone,U:Clone>(v: &[T], u: &[U]) -> ~[(T, U)] {
- let mut zipped = ~[];
- let sz = v.len();
- let mut i = 0u;
- assert_eq!(sz, u.len());
- while i < sz {
- zipped.push((v[i].clone(), u[i].clone()));
- i += 1u;
- }
- zipped
-}
-
-/**
- * Convert two vectors to a vector of pairs.
- *
- * Returns a vector of tuples, where the i-th tuple contains the
- * i-th elements from each of the input vectors.
- */
-pub fn zip<T, U>(mut v: ~[T], mut u: ~[U]) -> ~[(T, U)] {
- let mut i = v.len();
- assert_eq!(i, u.len());
- let mut w = with_capacity(i);
- while i > 0 {
- w.push((v.pop(),u.pop()));
- i -= 1;
- }
- w.reverse();
- w
-}
-
/**
* Iterate over all permutations of vector `v`.
*
/// elements at a time).
///
/// When the vector len is not evenly divided by the chunk size,
-/// the last slice of the iteration will be the remainer.
+/// the last slice of the iteration will be the remainder.
#[deriving(Clone)]
pub struct ChunkIter<'self, T> {
priv v: &'self [T],
}
impl<'self, T> Container for &'self [T] {
- /// Returns true if a vector contains no elements
- #[inline]
- fn is_empty(&self) -> bool {
- self.as_imm_buf(|_p, len| len == 0u)
- }
-
/// Returns the length of a vector
#[inline]
fn len(&self) -> uint {
}
impl<T> Container for ~[T] {
- /// Returns true if a vector contains no elements
- #[inline]
- fn is_empty(&self) -> bool {
- self.as_imm_buf(|_p, len| len == 0u)
- }
-
/// Returns the length of a vector
#[inline]
fn len(&self) -> uint {
* Sets the length of a vector
*
* This will explicitly set the size of the vector, without actually
- * modifing its buffers, so it is up to the caller to ensure that
+ * modifying its buffers, so it is up to the caller to ensure that
* the vector is actually the specified size.
*/
#[inline]
}
}
-impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
- fn from_iterator(iterator: &mut T) -> ~[A] {
+impl<A> FromIterator<A> for ~[A] {
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
let mut xs = with_capacity(lower);
for x in *iterator {
}
}
-impl<A, T: Iterator<A>> Extendable<A, T> for ~[A] {
- fn extend(&mut self, iterator: &mut T) {
+impl<A> Extendable<A> for ~[A] {
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T) {
let (lower, _) = iterator.size_hint();
let len = self.len();
self.reserve(len + lower);
#[test]
fn test_zip_unzip() {
- let v1 = ~[1, 2, 3];
- let v2 = ~[4, 5, 6];
-
- let z1 = zip(v1, v2);
-
- assert_eq!((1, 4), z1[0]);
- assert_eq!((2, 5), z1[1]);
- assert_eq!((3, 6), z1[2]);
+ let z1 = ~[(1, 4), (2, 5), (3, 6)];
let (left, right) = unzip(z1);
}
// a "Path" is essentially Rust's notion of a name;
-// for instance: core::cmp::Eq . It's represented
+// for instance: std::cmp::Eq . It's represented
// as a sequence of identifiers, along with a bunch
// of supporting information.
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
/* hold off on tests ... they appear in a later merge.
#[cfg(test)]
mod test {
- use core::option::{None, Option, Some};
- use core::uint;
+ use std::option::{None, Option, Some};
+ use std::uint;
use extra;
use codemap::*;
use super::*;
self.expr(span, ast::expr_fn_block(fn_decl, blk))
}
+ #[cfg(stage0)]
fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|| $blk_e )
}
+ #[cfg(not(stage0))]
+ fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
+ let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
+ quote_expr!(*self, || $blk_e )
+ }
+ #[cfg(stage0)]
fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|$ident| $blk_e )
}
+ #[cfg(not(stage0))]
+ fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
+ let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
+ quote_expr!(*self, |$ident| $blk_e )
+ }
fn lambda_expr(&self, span: span, ids: ~[ast::ident], expr: @ast::expr) -> @ast::expr {
self.lambda(span, ids, self.block_expr(expr))
use std::os;
+#[cfg(stage0)]
pub fn expand_option_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!");
};
MRExpr(e)
}
+#[cfg(not(stage0))]
+pub fn expand_option_env(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
+ -> base::MacResult {
+ let var = get_single_str_from_tts(cx, sp, tts, "option_env!");
+
+ let e = match os::getenv(var) {
+ None => quote_expr!(cx, ::std::option::None::<&'static str>),
+ Some(s) => quote_expr!(cx, ::std::option::Some($s))
+ };
+ MRExpr(e)
+}
-pub fn expand_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
+pub fn expand_env(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
- let exprs = get_exprs_from_tts(ext_cx, sp, tts);
+ let exprs = get_exprs_from_tts(cx, sp, tts);
if exprs.len() == 0 {
- ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments");
+ cx.span_fatal(sp, "env! takes 1 or 2 arguments");
}
- let var = expr_to_str(ext_cx, exprs[0], "expected string literal");
+ let var = expr_to_str(cx, exprs[0], "expected string literal");
let msg = match exprs.len() {
1 => fmt!("Environment variable %s not defined", var).to_managed(),
- 2 => expr_to_str(ext_cx, exprs[1], "expected string literal"),
- _ => ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments")
+ 2 => expr_to_str(cx, exprs[1], "expected string literal"),
+ _ => cx.span_fatal(sp, "env! takes 1 or 2 arguments")
};
let e = match os::getenv(var) {
- None => ext_cx.span_fatal(sp, msg),
- Some(s) => ext_cx.expr_str(sp, s.to_managed())
+ None => cx.span_fatal(sp, msg),
+ Some(s) => cx.expr_str(sp, s.to_managed())
};
MRExpr(e)
}
println(fmt!($($arg),+))
)
)
+
+ // NOTE: use this after a snapshot lands to abstract the details
+ // of the TLS interface.
+ macro_rules! local_data_key (
+ ($name:ident: $ty:ty) => (
+ static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+ );
+ (pub $name:ident: $ty:ty) => (
+ pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+ )
+ )
+
+ // externfn! declares a wrapper for an external function.
+ // It is intended to be used like:
+ //
+ // externfn!(#[nolink]
+ // #[abi = \"cdecl\"]
+ // fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
+ //
+ // Due to limitations in the macro parser, this pattern must be
+ // implemented with 4 distinct patterns (with attrs / without
+ // attrs CROSS with args / without ARGS).
+ //
+ // Also, this macro grammar allows for any number of return types
+ // because I couldn't figure out the syntax to specify at most one.
+ macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name() $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name();
+
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ }
+ );
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name($($arg_name),*);
+
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ }
+ );
+ ($($attrs:attr)* fn $name:ident () $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name() $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name();
+
+ $($attrs)*
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ }
+ );
+ ($($attrs:attr)* fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name($($arg_name),*);
+
+ $($attrs)*
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ }
+ )
+ )
+
}";
}
fn format_arg(&self, sp: span, arg: Either<uint, @str>,
ident: ast::ident) -> @ast::expr {
- let mut ty = match arg {
+ let ty = match arg {
Left(i) => self.arg_types[i].unwrap(),
Right(s) => *self.name_types.get(&s)
};
- // Default types to '?' if nothing else is specified.
- if ty == Unknown {
- ty = Known(@"?");
- }
let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident));
- match ty {
+ let fmt_trait = match ty {
+ Unknown => "Default",
Known(tyname) => {
- let fmt_trait = match tyname.as_slice() {
+ match tyname.as_slice() {
"?" => "Poly",
"b" => "Bool",
"c" => "Char",
`%s`", tyname));
"Dummy"
}
- };
- let format_fn = self.ecx.path_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of(fmt_trait),
- self.ecx.ident_of("fmt"),
- ]);
- self.ecx.expr_call_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of("argument"),
- ], ~[self.ecx.expr_path(format_fn), argptr])
+ }
}
String => {
- self.ecx.expr_call_global(sp, ~[
+ return self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argumentstr"),
], ~[argptr])
}
Unsigned => {
- self.ecx.expr_call_global(sp, ~[
+ return self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argumentuint"),
], ~[argptr])
}
- Unknown => { fail!() }
- }
+ };
+
+ let format_fn = self.ecx.path_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of(fmt_trait),
+ self.ecx.ident_of("fmt"),
+ ]);
+ self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argument"),
+ ], ~[self.ecx.expr_path(format_fn), argptr])
}
}
// Alas ... we write these out instead. All redundant.
- impl ToTokens for ast::ident {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for @ast::item {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl<'self> ToTokens for &'self [@ast::item] {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for ast::Ty {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl<'self> ToTokens for &'self [ast::Ty] {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for Generics {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for @ast::expr {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for ast::Block {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl<'self> ToTokens for &'self str {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for int {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i8 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i16 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i32 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i64 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for uint {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u8 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u16 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u32 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u64 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
+ macro_rules! impl_to_tokens(
+ ($t:ty) => (
+ impl ToTokens for $t {
+ fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
+ cx.parse_tts(self.to_source())
+ }
+ }
+ )
+ )
+
+ macro_rules! impl_to_tokens_self(
+ ($t:ty) => (
+ impl<'self> ToTokens for $t {
+ fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
+ cx.parse_tts(self.to_source())
+ }
+ }
+ )
+ )
+
+ impl_to_tokens!(ast::ident)
+ impl_to_tokens!(@ast::item)
+ impl_to_tokens_self!(&'self [@ast::item])
+ impl_to_tokens!(ast::Ty)
+ impl_to_tokens_self!(&'self [ast::Ty])
+ impl_to_tokens!(Generics)
+ impl_to_tokens!(@ast::expr)
+ impl_to_tokens!(ast::Block)
+ impl_to_tokens_self!(&'self str)
+ impl_to_tokens!(int)
+ impl_to_tokens!(i8)
+ impl_to_tokens!(i16)
+ impl_to_tokens!(i32)
+ impl_to_tokens!(i64)
+ impl_to_tokens!(uint)
+ impl_to_tokens!(u8)
+ impl_to_tokens!(u16)
+ impl_to_tokens!(u32)
+ impl_to_tokens!(u64)
pub trait ExtParseUtils {
fn parse_item(&self, s: @str) -> @ast::item;
pub fn expand_quote_tokens(cx: @ExtCtxt,
sp: span,
tts: &[ast::token_tree]) -> base::MacResult {
- base::MRExpr(expand_tts(cx, sp, tts))
+ let (cx_expr, expr) = expand_tts(cx, sp, tts);
+ base::MRExpr(expand_wrapper(cx, sp, cx_expr, expr))
}
pub fn expand_quote_expr(cx: @ExtCtxt,
fn expand_tts(cx: @ExtCtxt,
sp: span,
- tts: &[ast::token_tree]) -> @ast::expr {
+ tts: &[ast::token_tree]) -> (@ast::expr, @ast::expr) {
// NB: It appears that the main parser loses its mind if we consider
// $foo as a tt_nonterminal during the main parse, so we have to re-parse
tts.to_owned()
);
*p.quote_depth += 1u;
- let tts = p.parse_all_token_trees();
- p.abort_if_errors();
- // We want to emit a block expression that does a sequence of 'use's to
- // import the runtime module, followed by a tt-building expression.
+ let cx_expr = p.parse_expr();
+ if !p.eat(&token::COMMA) {
+ p.fatal("Expected token `,`");
+ }
- let uses = ~[ cx.view_use_glob(sp, ast::public,
- ids_ext(~[~"syntax",
- ~"ext",
- ~"quote",
- ~"rt"])) ];
+ let tts = p.parse_all_token_trees();
+ p.abort_if_errors();
// We also bind a single value, sp, to ext_cx.call_site()
//
// the site the string literal occurred, which was in a source file
// _other_ than the one the user has control over. For example, an
// error in a quote from the protocol compiler, invoked in user code
- // using macro_rules! for example, will be attributed to the macro_rules.rs file in
- // libsyntax, which the user might not even have source to (unless they
- // happen to have a compiler on hand). Over all, the phase distinction
+ // using macro_rules! for example, will be attributed to the macro_rules.rs
+ // file in libsyntax, which the user might not even have source to (unless
+ // they happen to have a compiler on hand). Over all, the phase distinction
// just makes quotes "hard to attribute". Possibly this could be fixed
// by recreating some of the original qq machinery in the tt regime
// (pushing fake FileMaps onto the parser to account for original sites
id_ext("tt"),
cx.expr_vec_uniq(sp, ~[]));
- cx.expr_block(
- cx.block_all(sp, uses,
- ~[stmt_let_sp,
- stmt_let_tt] + mk_tts(cx, sp, tts),
- Some(cx.expr_ident(sp, id_ext("tt")))))
+ let block = cx.expr_block(
+ cx.block_all(sp,
+ ~[],
+ ~[stmt_let_sp, stmt_let_tt] + mk_tts(cx, sp, tts),
+ Some(cx.expr_ident(sp, id_ext("tt")))));
+
+ (cx_expr, block)
+}
+
+fn expand_wrapper(cx: @ExtCtxt,
+ sp: span,
+ cx_expr: @ast::expr,
+ expr: @ast::expr) -> @ast::expr {
+ let uses = ~[ cx.view_use_glob(sp, ast::public,
+ ids_ext(~[~"syntax",
+ ~"ext",
+ ~"quote",
+ ~"rt"])) ];
+
+ let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr);
+
+ cx.expr_block(cx.block_all(sp, uses, ~[stmt_let_ext_cx], Some(expr)))
}
fn expand_parse_call(cx: @ExtCtxt,
parse_method: &str,
arg_exprs: ~[@ast::expr],
tts: &[ast::token_tree]) -> @ast::expr {
- let tts_expr = expand_tts(cx, sp, tts);
+ let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
let cfg_call = || cx.expr_method_call(
sp, cx.expr_ident(sp, id_ext("ext_cx")),
id_ext("parse_sess"), ~[]);
let new_parser_call =
- cx.expr_call_global(sp,
- ids_ext(~[~"syntax",
- ~"ext",
- ~"quote",
- ~"rt",
- ~"new_parser_from_tts"]),
- ~[parse_sess_call(),
- cfg_call(),
- tts_expr]);
-
- cx.expr_method_call(sp, new_parser_call,
- id_ext(parse_method),
- arg_exprs)
+ cx.expr_call(sp,
+ cx.expr_ident(sp, id_ext("new_parser_from_tts")),
+ ~[parse_sess_call(), cfg_call(), tts_expr]);
+
+ let expr = cx.expr_method_call(sp, new_parser_call, id_ext(parse_method),
+ arg_exprs);
+
+ expand_wrapper(cx, sp, cx_expr, expr)
}
use ast;
use codemap::{spanned, mk_sp};
-use codemap::BytePos;
use parse::common::*; //resolve bug?
use parse::token;
use parse::parser::Parser;
c => {
// So the error span points to the unrecognized character
rdr.peek_span = codemap::mk_sp(rdr.last_pos, rdr.pos);
- rdr.fatal(fmt!("unknown start of token: %d", c as int));
+ let mut cs = ~"";
+ char::escape_default(c, |c| cs.push_char(c));
+ rdr.fatal(fmt!("unknown start of token: %s", cs));
}
}
}
_ => {
p.fatal(
fmt!(
- "expected `;` or `}` but found `%s`",
+ "expected `;` or `{` but found `%s`",
self.this_token_to_str()
)
);
|p| p.parse_arg()
);
- let inputs = either::lefts(args_or_capture_items);
+ let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
let (ret_style, ret_ty) = self.parse_ret_ty();
ast::fn_decl {
let hi = self.span.hi;
- let inputs = either::lefts(args_or_capture_items);
+ let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
let (ret_style, ret_ty) = self.parse_ret_ty();
let fn_decl = ast::fn_decl {
};
ast::fn_decl {
- inputs: either::lefts(inputs_captures),
+ inputs: either::lefts(inputs_captures.move_iter()).collect(),
output: output,
cf: return_val,
}
"be", // 64
"pure", // 65
+ "yield", // 66
];
@ident_interner {
Once,
Priv,
Pub,
- Pure,
Ref,
Return,
Static,
// Reserved keywords
Be,
+ Pure,
+ Yield,
}
impl Keyword {
Once => ident { name: 50, ctxt: 0 },
Priv => ident { name: 51, ctxt: 0 },
Pub => ident { name: 52, ctxt: 0 },
- Pure => ident { name: 65, ctxt: 0 },
Ref => ident { name: 53, ctxt: 0 },
Return => ident { name: 54, ctxt: 0 },
Static => ident { name: 27, ctxt: 0 },
Use => ident { name: 61, ctxt: 0 },
While => ident { name: 62, ctxt: 0 },
Be => ident { name: 64, ctxt: 0 },
+ Pure => ident { name: 65, ctxt: 0 },
+ Yield => ident { name: 66, ctxt: 0 },
}
}
}
pub fn is_any_keyword(tok: &Token) -> bool {
match *tok {
token::IDENT(sid, false) => match sid.name {
- 8 | 27 | 32 .. 65 => true,
+ 8 | 27 | 32 .. 66 => true,
_ => false,
},
_ => false
pub fn is_reserved_keyword(tok: &Token) -> bool {
match *tok {
token::IDENT(sid, false) => match sid.name {
- 64 .. 65 => true,
+ 64 .. 66 => true,
_ => false,
},
_ => false,
#include "memory_region.h"
#include "boxed_region.h"
#include "rust_globals.h"
-#include "rust_env.h"
#include "rust_util.h"
// #define DUMP_BOXED_REGION
return RUNNING_ON_VALGRIND;
}
-extern int get_num_cpus();
+#if defined(__WIN32__)
+int
+get_num_cpus() {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+
+ return (int) sysinfo.dwNumberOfProcessors;
+}
+#elif defined(__BSD__)
+int
+get_num_cpus() {
+ /* swiped from http://stackoverflow.com/questions/150355/
+ programmatically-find-the-number-of-cores-on-a-machine */
+
+ unsigned int numCPU;
+ int mib[4];
+ size_t len = sizeof(numCPU);
+
+ /* set the mib for hw.ncpu */
+ mib[0] = CTL_HW;
+ mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
+
+ /* get the number of CPUs from the system */
+ sysctl(mib, 2, &numCPU, &len, NULL, 0);
+
+ if( numCPU < 1 ) {
+ mib[1] = HW_NCPU;
+ sysctl( mib, 2, &numCPU, &len, NULL, 0 );
+
+ if( numCPU < 1 ) {
+ numCPU = 1;
+ }
+ }
+ return numCPU;
+}
+#elif defined(__GNUC__)
+int
+get_num_cpus() {
+ return sysconf(_SC_NPROCESSORS_ONLN);
+}
+#endif
extern "C" CDECL uintptr_t
rust_get_num_cpus() {
return 0;
}
+static lock_and_signal env_lock;
+
+extern "C" CDECL void
+rust_take_env_lock() {
+ env_lock.lock();
+}
+
+extern "C" CDECL void
+rust_drop_env_lock() {
+ env_lock.unlock();
+}
+
+extern "C" CDECL unsigned int
+rust_valgrind_stack_register(void *start, void *end) {
+ return VALGRIND_STACK_REGISTER(start, end);
+}
+
+extern "C" CDECL void
+rust_valgrind_stack_deregister(unsigned int id) {
+ VALGRIND_STACK_DEREGISTER(id);
+}
+
//
// Local Variables:
// mode: C++
+++ /dev/null
-// Copyright 2012 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.
-
-// The runtime wants to pull a number of variables out of the
-// environment but calling getenv is not threadsafe, so every value
-// that might come from the environment is loaded here, once, during
-// init.
-
-#include "sync/lock_and_signal.h"
-#include "rust_env.h"
-
-// The environment variables that the runtime knows about
-#define RUST_THREADS "RUST_THREADS"
-#define RUST_MIN_STACK "RUST_MIN_STACK"
-#define RUST_MAX_STACK "RUST_MAX_STACK"
-#define RUST_LOG "RUST_LOG"
-#define DETAILED_LEAKS "DETAILED_LEAKS"
-#define RUST_SEED "RUST_SEED"
-#define RUST_POISON_ON_FREE "RUST_POISON_ON_FREE"
-#define RUST_DEBUG_MEM "RUST_DEBUG_MEM"
-#define RUST_DEBUG_BORROW "RUST_DEBUG_BORROW"
-
-#define DEFAULT_RUST_MIN_STACK_32 0x300
-#define DEFAULT_RUST_MIN_STACK_64 0x400000
-
-static lock_and_signal env_lock;
-
-extern "C" CDECL void
-rust_take_env_lock() {
- env_lock.lock();
-}
-
-extern "C" CDECL void
-rust_drop_env_lock() {
- env_lock.unlock();
-}
-
-#if defined(__WIN32__)
-int
-get_num_cpus() {
- SYSTEM_INFO sysinfo;
- GetSystemInfo(&sysinfo);
-
- return (int) sysinfo.dwNumberOfProcessors;
-}
-#elif defined(__BSD__)
-int
-get_num_cpus() {
- /* swiped from http://stackoverflow.com/questions/150355/
- programmatically-find-the-number-of-cores-on-a-machine */
-
- unsigned int numCPU;
- int mib[4];
- size_t len = sizeof(numCPU);
-
- /* set the mib for hw.ncpu */
- mib[0] = CTL_HW;
- mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
-
- /* get the number of CPUs from the system */
- sysctl(mib, 2, &numCPU, &len, NULL, 0);
-
- if( numCPU < 1 ) {
- mib[1] = HW_NCPU;
- sysctl( mib, 2, &numCPU, &len, NULL, 0 );
-
- if( numCPU < 1 ) {
- numCPU = 1;
- }
- }
- return numCPU;
-}
-#elif defined(__GNUC__)
-int
-get_num_cpus() {
- return sysconf(_SC_NPROCESSORS_ONLN);
-}
-#endif
-
-static int
-get_num_threads()
-{
- char *env = getenv(RUST_THREADS);
- if(env) {
- int num = atoi(env);
- if(num > 0)
- return num;
- }
- return get_num_cpus();
-}
-
-static size_t
-get_min_stk_size() {
- char *minsz = getenv(RUST_MIN_STACK);
- if(minsz) {
- return strtol(minsz, NULL, 0);
- }
- else if (sizeof(size_t) > 4) {
- return DEFAULT_RUST_MIN_STACK_64;
- } else {
- return DEFAULT_RUST_MIN_STACK_32;
- }
-}
-
-static size_t
-get_max_stk_size() {
- char *maxsz = getenv(RUST_MAX_STACK);
- if (maxsz) {
- return strtol(maxsz, NULL, 0);
- }
- else {
- return 1024*1024*1024;
- }
-}
-
-static char*
-copyenv(const char* name) {
- char *envvar = getenv(name);
- if (!envvar) {
- return NULL;
- } else {
- size_t slen = strlen(envvar);
- size_t buflen = slen + 1;
- char *var = (char*)malloc(buflen);
- memset(var, 0, buflen);
- strncpy(var, envvar, slen);
- return var;
- }
-}
-
-rust_env*
-load_env(int argc, char **argv) {
- scoped_lock with(env_lock);
-
- rust_env *env = (rust_env*)malloc(sizeof(rust_env));
-
- env->num_sched_threads = (size_t)get_num_threads();
- env->min_stack_size = get_min_stk_size();
- env->max_stack_size = get_max_stk_size();
- env->logspec = copyenv(RUST_LOG);
- env->detailed_leaks = getenv(DETAILED_LEAKS) != NULL;
- env->rust_seed = copyenv(RUST_SEED);
- env->poison_on_free = getenv(RUST_POISON_ON_FREE) != NULL;
- env->argc = argc;
- env->argv = argv;
- env->debug_mem = getenv(RUST_DEBUG_MEM) != NULL;
- env->debug_borrow = getenv(RUST_DEBUG_BORROW) != NULL;
- return env;
-}
-
-void
-free_env(rust_env *env) {
- free(env->logspec);
- free(env->rust_seed);
- free(env);
-}
+++ /dev/null
-// Copyright 2012 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.
-
-
-#ifndef RUST_ENV_H
-#define RUST_ENV_H
-
-#include "rust_globals.h"
-
-// Avoiding 'bool' type here since I'm not sure it has a standard size
-typedef uint8_t rust_bool;
-
-struct rust_env {
- size_t num_sched_threads;
- size_t min_stack_size;
- size_t max_stack_size;
- char* logspec;
- rust_bool detailed_leaks;
- char* rust_seed;
- rust_bool poison_on_free;
- int argc;
- char **argv;
- rust_bool debug_mem;
- rust_bool debug_borrow;
-};
-
-rust_env* load_env(int argc, char **argv);
-void free_env(rust_env *rust_env);
-
-#endif
#define CDECL __cdecl
#endif
#ifndef FASTCALL
-#define FASTCALL __fastcall
#endif
#else
#define CDECL __attribute__((cdecl))
-#define FASTCALL __attribute__((fastcall))
#endif
#else
#define CDECL
-#define FASTCALL
#endif
#define CHECKED(call) \
} \
}
-#define MUST_CHECK __attribute__((warn_unused_result))
-
-#define PTR "0x%" PRIxPTR
-
-// This accounts for logging buffers.
-static size_t const BUF_BYTES = 2048;
-
-#define INIT_TASK_ID 1
-
-// The error status to use when the process fails
-#define PROC_FAIL_CODE 101
-
-// A cond(ition) is something we can block on. This can be a channel
-// (writing), a port (reading) or a task (waiting).
-struct rust_cond { };
-
-extern void* global_crate_map;
-
#endif /* RUST_GLOBALS_H */
*/
-#include "rust_log.h"
#include "rust_crate_map.h"
#include "util/array_list.h"
#include "rust_util.h"
size_t level;
};
+
+const uint32_t log_err = 1;
+const uint32_t log_warn = 2;
+const uint32_t log_info = 3;
+const uint32_t log_debug = 4;
+
const size_t max_log_directives = 255;
const size_t max_log_level = 255;
const size_t default_log_level = log_err;
// This is a rather ugly parser for strings in the form
// "crate1,crate2.mod3,crate3.x=1". Log levels are 0-255,
-// with the most likely ones being 0-3 (defined in core::).
+// with the most likely ones being 0-3 (defined in std::).
size_t parse_logging_spec(char* spec, log_directive* dirs) {
size_t dir = 0;
while (dir < max_log_directives && *spec) {
}
}
-void update_module_map(const mod_entry* map, log_directive* dirs,
- size_t n_dirs, size_t *n_matches) {
- update_entry_args args = { dirs, n_dirs, n_matches };
- iter_module_map(map, update_entry, &args);
-}
-
void update_crate_map(const cratemap* map, log_directive* dirs,
size_t n_dirs, size_t *n_matches) {
update_entry_args args = { dirs, n_dirs, n_matches };
iter_crate_map(map, print_mod_name, NULL);
}
-// These are pseudo-modules used to control logging in the runtime.
-
-uint32_t log_rt_mem;
-uint32_t log_rt_box;
-uint32_t log_rt_comm;
-uint32_t log_rt_task;
-uint32_t log_rt_dom;
-uint32_t log_rt_trace;
-uint32_t log_rt_cache;
-uint32_t log_rt_upcall;
-uint32_t log_rt_timer;
-uint32_t log_rt_gc;
-uint32_t log_rt_stdlib;
-uint32_t log_rt_kern;
-uint32_t log_rt_backtrace;
-uint32_t log_rt_callback;
-
-static const mod_entry _rt_module_map[] =
- {{"::rt::mem", &log_rt_mem},
- {"::rt::box", &log_rt_box},
- {"::rt::comm", &log_rt_comm},
- {"::rt::task", &log_rt_task},
- {"::rt::dom", &log_rt_dom},
- {"::rt::trace", &log_rt_trace},
- {"::rt::cache", &log_rt_cache},
- {"::rt::upcall", &log_rt_upcall},
- {"::rt::timer", &log_rt_timer},
- {"::rt::gc", &log_rt_gc},
- {"::rt::stdlib", &log_rt_stdlib},
- {"::rt::kern", &log_rt_kern},
- {"::rt::backtrace", &log_rt_backtrace},
- {"::rt::callback", &log_rt_callback},
- {NULL, NULL}};
-
void update_log_settings(void* crate_map, char* settings) {
char* buffer = NULL;
log_directive dirs[256];
}
size_t n_matches = 0;
- update_module_map(_rt_module_map, &dirs[0], n_dirs, &n_matches);
update_crate_map((const cratemap*)crate_map, &dirs[0],
n_dirs, &n_matches);
+++ /dev/null
-// Copyright 2012 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.
-
-#ifndef RUST_LOG_H
-#define RUST_LOG_H
-
-#include "rust_globals.h"
-
-const uint32_t log_err = 1;
-const uint32_t log_warn = 2;
-const uint32_t log_info = 3;
-const uint32_t log_debug = 4;
-
-void update_log_settings(void* crate_map, char* settings);
-
-extern uint32_t log_rt_mem;
-extern uint32_t log_rt_box;
-extern uint32_t log_rt_comm;
-extern uint32_t log_rt_task;
-extern uint32_t log_rt_dom;
-extern uint32_t log_rt_trace;
-extern uint32_t log_rt_cache;
-extern uint32_t log_rt_upcall;
-extern uint32_t log_rt_timer;
-extern uint32_t log_rt_gc;
-extern uint32_t log_rt_stdlib;
-extern uint32_t log_rt_kern;
-extern uint32_t log_rt_backtrace;
-extern uint32_t log_rt_callback;
-
-#endif /* RUST_LOG_H */
+++ /dev/null
-// Copyright 2012 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.
-
-
-#ifndef RUST_REFCOUNT_H
-#define RUST_REFCOUNT_H
-
-#include "sync/sync.h"
-
-// Refcounting defines
-typedef unsigned long ref_cnt_t;
-
-#define RUST_ATOMIC_REFCOUNT() \
-private: \
- intptr_t ref_count; \
-public: \
- void ref() { \
- intptr_t old = sync::increment(ref_count); \
- assert(old > 0); \
- } \
- void deref() { if(0 == sync::decrement(ref_count)) { delete_this(); } } \
- intptr_t get_ref_count() { return sync::read(ref_count); }
-
-#endif
+++ /dev/null
-// Copyright 2012 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.
-
-#ifndef RUST_SIGNAL_H
-#define RUST_SIGNAL_H
-
-// Just an abstract class that represents something that can be signalled
-class rust_signal {
-public:
- virtual void signal() = 0;
- virtual ~rust_signal() {}
- rust_signal() {}
-
-private:
- // private and undefined to disable copying
- rust_signal(const rust_signal& rhs);
- rust_signal& operator=(const rust_signal& rhs);
-};
-
-#endif /* RUST_SIGNAL_H */
+++ /dev/null
-// Copyright 2012 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.
-
-
-#include "rust_stack.h"
-#include "vg/valgrind.h"
-#include "vg/memcheck.h"
-
-#include <cstdio>
-
-#ifdef _LP64
-const uintptr_t canary_value = 0xABCDABCDABCDABCD;
-#else
-const uintptr_t canary_value = 0xABCDABCD;
-#endif
-
-void
-register_valgrind_stack(stk_seg *stk) {
- stk->valgrind_id =
- VALGRIND_STACK_REGISTER(&stk->data[0],
- stk->end);
-}
-
-void
-reuse_valgrind_stack(stk_seg *stk, uint8_t *sp) {
- // Establish that the stack is accessible. This must be done when reusing
- // old stack segments, since the act of popping the stack previously
- // caused valgrind to consider the whole thing inaccessible.
- assert(sp >= stk->data && sp <= (uint8_t*) stk->end
- && "Stack pointer must be inside stack segment");
- size_t sz = stk->end - (uintptr_t)sp;
- (void) VALGRIND_MAKE_MEM_UNDEFINED(sp, sz);
- (void) sz;
-}
-
-void
-deregister_valgrind_stack(stk_seg *stk) {
- VALGRIND_STACK_DEREGISTER(stk->valgrind_id);
-}
-
-void
-add_stack_canary(stk_seg *stk) {
- stk->canary = canary_value;
-}
-
-void
-check_stack_canary(stk_seg *stk) {
- assert(stk->canary == canary_value && "Somebody killed the canary");
-}
-
-// XXX: Duplication here between the local and exchange heap constructors
-
-stk_seg *
-create_stack(memory_region *region, size_t sz) {
- size_t total_sz = sizeof(stk_seg) + sz;
- stk_seg *stk = (stk_seg *)region->malloc(total_sz, "stack");
- memset(stk, 0, sizeof(stk_seg));
- stk->end = (uintptr_t) &stk->data[sz];
- stk->is_big = 0;
- add_stack_canary(stk);
- register_valgrind_stack(stk);
- return stk;
-}
-
-void
-destroy_stack(memory_region *region, stk_seg *stk) {
- deregister_valgrind_stack(stk);
- region->free(stk);
-}
-
-stk_seg *
-create_exchange_stack(rust_exchange_alloc *exchange, size_t sz) {
- size_t total_sz = sizeof(stk_seg) + sz;
- stk_seg *stk = (stk_seg *)exchange->malloc(total_sz);
- memset(stk, 0, sizeof(stk_seg));
- stk->end = (uintptr_t) &stk->data[sz];
- stk->is_big = 0;
- add_stack_canary(stk);
- register_valgrind_stack(stk);
- return stk;
-}
-
-void
-destroy_exchange_stack(rust_exchange_alloc *exchange, stk_seg *stk) {
- deregister_valgrind_stack(stk);
- exchange->free(stk);
-}
-
-
-extern "C" CDECL unsigned int
-rust_valgrind_stack_register(void *start, void *end) {
- return VALGRIND_STACK_REGISTER(start, end);
-}
-
-extern "C" CDECL void
-rust_valgrind_stack_deregister(unsigned int id) {
- VALGRIND_STACK_DEREGISTER(id);
-}
+++ /dev/null
-// Copyright 2012 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.
-
-#ifndef RUST_STACK_H
-#define RUST_STACK_H
-
-#include "rust_globals.h"
-#include "rust_exchange_alloc.h"
-#include "memory_region.h"
-
-struct rust_task;
-
-struct stk_seg {
- stk_seg *prev;
- stk_seg *next;
- uintptr_t end;
- unsigned int valgrind_id;
- uint8_t is_big;
-
- rust_task *task;
- uintptr_t canary;
-
- uint8_t data[];
-};
-
-stk_seg *
-create_stack(memory_region *region, size_t sz);
-
-void
-destroy_stack(memory_region *region, stk_seg *stk);
-
-stk_seg *
-create_exchange_stack(rust_exchange_alloc *exchange, size_t sz);
-
-void
-destroy_exchange_stack(rust_exchange_alloc *exchange, stk_seg *stk);
-
-// Must be called before each time a stack is reused to tell valgrind
-// that the stack is accessible.
-void
-reuse_valgrind_stack(stk_seg *stk, uint8_t *sp);
-
-// Run a sanity check
-void
-check_stack_canary(stk_seg *stk);
-
-#endif /* RUST_STACK_H */
#define RUST_TYPE_H
#include "rust_globals.h"
-#include "rust_refcount.h"
struct rust_opaque_box;
typedef void CDECL (glue_fn)(void *,
void *);
+typedef unsigned long ref_cnt_t;
+
// Corresponds to the boxed data in the @ region. The body follows the
// header; you can obtain a ptr via box_body() below.
struct rust_opaque_box {
size_t borrow_offset;
};
-extern "C" type_desc *rust_clone_type_desc(type_desc*);
-
#endif
//
*/
#include "rust_globals.h"
-#include "rust_upcall.h"
#include "rust_util.h"
//Unwinding ABI declarations.
+++ /dev/null
-// Copyright 2012 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.
-
-#ifndef RUST_UPCALL_H
-#define RUST_UPCALL_H
-
-#endif
#include <limits.h>
#include "rust_exchange_alloc.h"
#include "rust_type.h"
-#include "rust_env.h"
extern struct type_desc str_body_tydesc;
#include "rust_globals.h"
-// extern fn pointers
-typedef void (*extern_async_op_cb)(uv_loop_t* loop, void* data,
- uv_async_t* op_handle);
-typedef void (*extern_simple_cb)(uint8_t* id_buf, void* loop_data);
-typedef void (*extern_close_cb)(uint8_t* id_buf, void* handle,
- void* data);
-
-// data types
-#define RUST_UV_HANDLE_LEN 16
-
-struct handle_data {
- uint8_t id_buf[RUST_UV_HANDLE_LEN];
- extern_simple_cb cb;
- extern_close_cb close_cb;
-};
-
-static void
-foreign_timer_cb(uv_timer_t* handle, int status) {
- handle_data* handle_d = (handle_data*)handle->data;
- void* loop_data = handle->loop->data;
- handle_d->cb(handle_d->id_buf, loop_data);
-}
-
-static void
-foreign_close_cb(uv_handle_t* handle) {
- handle_data* data = (handle_data*)handle->data;
- data->close_cb(data->id_buf, handle, handle->loop->data);
-}
extern "C" void*
rust_uv_loop_new() {
return (void*)uv_loop_new();
uv_walk(loop, cb, arg);
}
-extern "C" void
-rust_uv_hilvl_close(uv_handle_t* handle, extern_close_cb cb) {
- handle_data* data = (handle_data*)handle->data;
- data->close_cb = cb;
- uv_close(handle, foreign_close_cb);
-}
-
extern "C" void
rust_uv_async_send(uv_async_t* handle) {
uv_async_send(handle);
return uv_async_init(loop_handle, async_handle, cb);
}
-extern "C" void
-rust_uv_hilvl_timer_start(uv_timer_t* the_timer, uint32_t timeout,
- uint32_t repeat) {
- uv_timer_start(the_timer, foreign_timer_cb, timeout, repeat);
-}
-
extern "C" int
rust_uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) {
return uv_timer_init(loop, timer);
return uv_accept(server, client);
}
-extern "C" size_t
-rust_uv_helper_uv_tcp_t_size() {
- return sizeof(uv_tcp_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_connect_t_size() {
- return sizeof(uv_connect_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_buf_t_size() {
- return sizeof(uv_buf_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_write_t_size() {
- return sizeof(uv_write_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_err_t_size() {
- return sizeof(uv_err_t);
-}
-extern "C" size_t
-rust_uv_helper_sockaddr_in_size() {
- return sizeof(sockaddr_in);
-}
-extern "C" size_t
-rust_uv_helper_sockaddr_in6_size() {
- return sizeof(sockaddr_in6);
-}
-extern "C" size_t
-rust_uv_helper_uv_async_t_size() {
- return sizeof(uv_async_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_timer_t_size() {
- return sizeof(uv_timer_t);
-}
-extern "C" size_t
-rust_uv_helper_addr_in_size() {
- return sizeof(sockaddr_in6);
-}
-extern "C" size_t
-rust_uv_helper_uv_getaddrinfo_t_size() {
- return sizeof(uv_getaddrinfo_t);
-}
-extern "C" size_t
-rust_uv_helper_addrinfo_size() {
- return sizeof(addrinfo);
-}
-extern "C" unsigned int
-rust_uv_helper_get_INADDR_NONE() {
- return INADDR_NONE;
-}
extern "C" uv_stream_t*
rust_uv_get_stream_handle_from_connect_req(uv_connect_t* connect) {
return connect->handle;
rust_uv_loop_set_data
rust_uv_run
rust_uv_close
-rust_uv_hilvl_close
rust_uv_async_send
rust_uv_async_init
-rust_uv_hilvl_timer_start
rust_uv_timer_init
rust_uv_timer_start
rust_uv_timer_stop
rust_uv_get_next_addrinfo
rust_uv_addrinfo_as_sockaddr_in
rust_uv_addrinfo_as_sockaddr_in6
-rust_uv_helper_uv_tcp_t_size
-rust_uv_helper_uv_connect_t_size
-rust_uv_helper_uv_buf_t_size
-rust_uv_helper_uv_write_t_size
-rust_uv_helper_uv_err_t_size
-rust_uv_helper_sockaddr_in_size
-rust_uv_helper_sockaddr_in6_size
-rust_uv_helper_addr_in_size
-rust_uv_helper_addrinfo_size
-rust_uv_helper_uv_getaddrinfo_t_size
-rust_uv_helper_get_INADDR_NONE
-rust_uv_helper_uv_async_t_size
-rust_uv_helper_uv_timer_t_size
rust_uv_get_stream_handle_from_connect_req
rust_uv_get_stream_handle_from_write_req
rust_uv_get_loop_for_uv_handle
extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) {
unwrap<GlobalValue>(Value)->setUnnamedAddr(Unnamed);
}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateTemplateTypeParameter(
+ DIBuilderRef Builder,
+ LLVMValueRef Scope,
+ const char* Name,
+ LLVMValueRef Ty,
+ LLVMValueRef File = 0,
+ unsigned LineNo = 0,
+ unsigned ColumnNo = 0)
+{
+ return wrap(Builder->createTemplateTypeParameter(
+ unwrapDI<DIDescriptor>(Scope),
+ Name,
+ unwrapDI<DIType>(Ty),
+ unwrapDI<MDNode*>(File),
+ LineNo,
+ ColumnNo));
+}
LLVMDIBuilderCreateEnumerator
LLVMDIBuilderCreateEnumerationType
LLVMDIBuilderCreateUnionType
+LLVMDIBuilderCreateTemplateTypeParameter
LLVMSetUnnamedAddr
+S 2013-08-14 e7b5729
+ freebsd-x86_64 9de0b5583a5c4413f9e77df7071498385e936dd2
+ linux-i386 29119a9072f74c639c2bad998edc40e582da540e
+ linux-x86_64 319fb73727da9a8e4dd6debe37e7647e40ed361b
+ macos-i386 f74a0f02efec35e327a9c819c5c8347579d1b7fe
+ macos-x86_64 f44aba76e9d7a9a28b8a6dd78f14576e7c84fbf3
+ winnt-i386 49dd1f264e17e6cd929c827ccbe23ee09058c7fc
+
S 2013-08-12 ecfc9a8
freebsd-x86_64 ae903580d6328b8517dc64b013c1b0740bfa4e83
linux-i386 3076bf032ce980157a894a0a4446902ba8b1783d
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::task;
pub fn foo<T:Send + Clone>(x: T) -> Port<T> {
// except according to those terms.
pub mod kitties {
- use std::uint;
-
pub struct cat {
priv meows : uint,
how_hungry : int,
how_hungry: in_y
}
}
-
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::to_str::*;
-
pub mod kitty {
pub struct cat {
priv meows : uint,
}
impl add for name_pool {
- fn add(&self, s: ~str) {
+ fn add(&self, _s: ~str) {
}
}
}
pub fn nominal() -> e { e_val }
-pub fn nominal_eq(e1: e, e2: e) -> bool { true }
+pub fn nominal_eq(_e1: e, _e2: e) -> bool { true }
impl Eq for e {
fn eq(&self, other: &e) -> bool { nominal_eq(*self, *other) }
pub fn nominal() -> e { e_val }
-pub fn nominal_neq(e1: e, e2: e) -> bool { false }
+pub fn nominal_neq(_e1: e, _e2: e) -> bool { false }
pub fn f() -> int { 20 }
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
--- /dev/null
+// 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.
+
+#[link(name="iss6919_3", vers="0.1")];
+
+// part of issue-6919.rs
+
+struct C<'self> {
+ k: &'self fn(),
+}
+
+fn no_op() { }
+pub static D : C<'static> = C {
+ k: no_op
+};
+
}
fn init() -> arc_destruct<context_res> {
- unsafe {
- arc(context_res())
- }
+ arc(context_res())
}
struct context_res {
enum maybe<T> { just(T), nothing }
impl <T:Clone> Index<uint,T> for maybe<T> {
- fn index(&self, idx: &uint) -> T {
+ fn index(&self, _idx: &uint) -> T {
match self {
&just(ref t) => (*t).clone(),
¬hing => { fail!(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
extern mod issue_2316_a;
pub mod cloth {
--- /dev/null
+// 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.
+
+pub trait Foo {
+ fn bar();
+}
+
--- /dev/null
+// 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.
+
+// for this issue, this code must be built in a library
+
+use std::cast;
+
+trait A {}
+struct B;
+impl A for B {}
+
+fn bar<T>(_: &mut A, _: &T) {}
+
+fn foo<T>(t: &T) {
+ let b = B;
+ bar(unsafe { cast::transmute(&b as &A) }, t)
+}
+
pub fn f() {
let x = S { x: 1 };
let y = x;
- let z = y;
+ let _z = y;
}
trait B<T> {
fn thing<U>(&self, x: T, y: U) -> (T, U) { (x, y) }
- fn staticthing<U>(z: &Self, x: T, y: U) -> (T, U) { (x, y) }
+ fn staticthing<U>(_z: &Self, x: T, y: U) -> (T, U) { (x, y) }
}
impl<T> B<T> for int { }
extern mod extra;
use extra::time::precise_time_s;
-use std::int;
use std::io;
use std::os;
use std::rand::RngUtil;
use std::rand;
-use std::result;
use std::str;
-use std::uint;
use std::util;
use std::vec;
use extra::future;
use extra::time;
use std::cell::Cell;
-use std::io;
use std::os;
use std::uint;
use extra::future;
use extra::time;
use std::cell::Cell;
-use std::io;
use std::os;
use std::uint;
// Perlin noise benchmark from https://gist.github.com/1170424
use std::float;
-use std::int;
use std::rand::{Rng, RngUtil};
use std::rand;
extern mod extra;
-use std::task::spawn;
use std::os;
use std::uint;
use std::rt::test::spawntask_later;
extern mod extra;
-use std::task::spawn;
use std::os;
use std::uint;
use std::rt::test::spawntask_later;
extern mod extra;
use std::int;
-use std::io;
use std::os;
fn ack(m: int, n: int) -> int {
use std::os;
use std::rand::Rng;
use std::rand;
-use std::result;
use std::str;
-use std::uint;
static LINE_LENGTH: uint = 60u;
extern mod extra;
use std::int;
-use std::io;
use std::os;
fn fib(n: int) -> int {
use std::io;
use std::option;
use std::os;
-use std::result;
use std::str;
use std::task;
use std::util;
use std::io::{ReaderUtil, WriterUtil};
use std::io;
use std::os;
-use std::u8;
use std::uint;
use std::unstable::intrinsics::cttz16;
use std::vec;
do task::spawn_supervised {
let c = c.take();
if gens_left & 1 == 1 {
- task::yield(); // shake things up a bit
+ task::deschedule(); // shake things up a bit
}
if gens_left > 0 {
child_generation(gens_left - 1, c); // recurse
#[no_mangle]
fn test() {
- let x = foo(10);
+ let _x = foo(10);
}
use std::local_data;
-static key: local_data::Key<@&int> = &local_data::Key;
+local_data_key!(key: @&int)
//~^ ERROR only 'static is allowed
fn main() {}
+++ /dev/null
-// Copyright 2012 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.
-
-use std::uint;
-
-fn uuid() -> uint { fail!(); }
-
-fn from_str(s: ~str) -> uint { fail!(); }
-fn to_str(u: uint) -> ~str { fail!(); }
-fn uuid_random() -> uint { fail!(); }
-
-fn main() {
- do range(0u, 100000).advance |_i| { //~ ERROR Do-block body must return bool, but
- };
- // should get a more general message if the callback
- // doesn't return nil
- do range(0u, 100000).advance |_i| { //~ ERROR mismatched types
- ~"str"
- };
-}
+++ /dev/null
-// Copyright 2012 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.
-
-fn main() {
- fn take_block(f: &fn() -> bool) -> bool { f() }
- do take_block {}; //~ ERROR Do-block body must return bool, but returns () here. Perhaps
-}
--- /dev/null
+// 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.
+
+// aux-build:issue_3907.rs
+extern mod issue_3907;
+
+type Foo = issue_3907::Foo; //~ ERROR: reference to trait
+
+struct S {
+ name: int
+}
+
+impl Foo for S { //~ ERROR: Foo is not a trait
+ fn bar() { }
+}
+
+fn main() {
+ let s = S {
+ name: 0
+ };
+ s.bar();
+}
+
--- /dev/null
+// 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.
+
+struct Foo {
+ foo: int,
+}
+
+struct Bar {
+ bar: int,
+}
+
+impl Bar {
+ fn make_foo (&self, i: int) -> ~Foo {
+ return ~Foo { nonexistent: self, foo: i }; //~ ERROR: no field named
+ }
+}
+
+fn main () {
+ let bar = Bar { bar: 1 };
+ let foo = bar.make_foo(2);
+ println(fmt!("%d", foo.foo));
+}
// except according to those terms.
// xfail-test
-use core::io::ReaderUtil;
-use core::io::Reader;
+use std::io::ReaderUtil;
+use std::io::Reader;
fn bar(r:@ReaderUtil) -> ~str { r.read_line() }
--- /dev/null
+// 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.
+
+trait Foo { fn a() } //~ ERROR expected `;` or `{` but found `}`
+
+fn main() {}
// Exercise the unused_unsafe attribute in some positive and negative cases
+#[allow(cstack)];
#[deny(unused_unsafe)];
mod foo {
}
}
}
+
unsafe fn good3() { foo::bar() }
fn good4() { unsafe { foo::bar() } }
--- /dev/null
+// 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.
+
+use std::local_data;
+
+// check that the local data keys are private by default.
+
+mod bar {
+ local_data_key!(baz: float)
+}
+
+fn main() {
+ local_data::set(bar::baz, -10.0);
+ //~^ ERROR unresolved name `bar::baz`
+}
fn main() {
- let ext_cx = mk_ctxt();
+ let cx = mk_ctxt();
- let abc = quote_expr!(23);
+ let abc = quote_expr!(cx, 23);
check_pp(abc, pprust::print_expr, "23");
- let expr3 = quote_expr!(2 - $abcd + 7); //~ ERROR unresolved name: abcd
+ let expr3 = quote_expr!(cx, 2 - $abcd + 7); //~ ERROR unresolved name: abcd
check_pp(expr3, pprust::print_expr, "2 - 23 + 7");
}
fn main() {
- let ext_cx = mk_ctxt();
+ let cx = mk_ctxt();
- let stmt = quote_stmt!(let x int = 20;); //~ ERROR expected end-of-string
+ let stmt = quote_stmt!(cx, let x int = 20;); //~ ERROR expected end-of-string
check_pp(*stmt, pprust::print_stmt, "");
}
--- /dev/null
+// 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.
+
+fn foo() -> int { 23 }
+
+static a: [int, ..2] = [foo(), ..2]; //~ ERROR: function calls in constants are limited to struct and enum constructors
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//error-pattern:libc::c_int or libc::c_long should be used
+#[forbid(ctypes)];
+
mod xx {
extern {
- pub fn strlen(str: *u8) -> uint;
- pub fn foo(x: int, y: uint);
+ pub fn strlen(str: *u8) -> uint; //~ ERROR found rust type `uint`
+ pub fn foo(x: int, y: uint); //~ ERROR found rust type `int`
+ //~^ ERROR found rust type `uint`
}
}
fn main() {
- // let it fail to verify warning message
- fail!()
}
// debugger:print f64
// check:$15 = 3.5
+#[allow(unused_variable)];
+
fn main() {
let b: bool = false;
let i: int = -1;
// debugger:print *f64_ref
// check:$15 = 3.5
+#[allow(unused_variable)];
+
fn main() {
let bool_val: bool = true;
let bool_ref: &bool = &bool_val;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *the_c_ref
// check:$3 = TheC
+#[allow(unused_variable)];
+
enum ABC { TheA, TheB, TheC }
fn main() {
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *univariant_ref
// check:$3 = {4820353753753434}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *f64_ref
// check:$15 = 3.5
+#[allow(unused_variable)];
fn main() {
let bool_box: @bool = @true;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *unique_val_interior_ref_2
// check:$10 = 26.5
-
+#[allow(unused_variable)];
struct SomeStruct {
x: int,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *unique_val_ref
// check:$4 = {-17, -22}
+#[allow(unused_variable)];
+
fn main() {
let stack_val: (i16, f32) = (-14, -19f32);
let stack_val_ref: &(i16, f32) = &stack_val;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *f64_ref
// check:$15 = 3.5
+#[allow(unused_variable)];
+
fn main() {
let bool_box: ~bool = ~true;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print d->val
// check:$4 = false
+#[allow(unused_variable)];
+
fn main() {
let a = ~1;
let b = ~(2, 3.5);
// debugger:print managed_dtor->val
// check:$4 = {x = 33, y = 333, z = 3333, w = 33333}
+#[allow(unused_variable)];
+
struct StructWithSomePadding {
x: i16,
y: i32,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *((uint64_t[4]*)(unique->elements))
// check:$4 = {10, 11, 12, 13}
+#[allow(unused_variable)];
+
fn main() {
let managed: @[i64] = @[7, 8, 9];
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// Does not work yet, see issue #8512
+// xfail-test
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print s
+// check:$1 = {a = 1, b = 2.5}
+// debugger:continue
+
+#[deriving(Clone)]
+struct Struct {
+ a: int,
+ b: float
+}
+
+fn fun(s: Struct) {
+ zzz();
+}
+
+fn main() {
+ fun(Struct { a: 1, b: 2.5 });
+}
+
+fn zzz() {()}
// debugger:print struct_with_drop
// check:$7 = {{a = OneHundred, b = Vienna}, 9}
+#[allow(unused_variable)];
+
enum AnEnum {
OneHundred = 100,
OneThousand = 1000,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print single_variant
// check:$7 = TheOnlyVariant
+#[allow(unused_variable)];
+
enum AutoDiscriminant {
One,
Two,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print x
+// check:$1 = 0.5
+// debugger:print y
+// check:$2 = 10
+// debugger:continue
+
+// debugger:finish
+// debugger:print *x
+// check:$3 = 29
+// debugger:print *y
+// check:$4 = 110
+// debugger:continue
+
+fn some_generic_fun<T1, T2>(a: T1, b: T2) -> (T2, T1) {
+
+ let closure = |x, y| {
+ zzz();
+ (y, x)
+ };
+
+ closure(a, b)
+}
+
+fn main() {
+ some_generic_fun(0.5, 10);
+ some_generic_fun(&29, ~110);
+}
+
+fn zzz() {()}
// check:$49 = 62
// debugger:continue
+#[allow(unused_variable)];
struct Struct {
a: i64,
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *nn
// check:$43 = 56
+#[allow(unused_variable)];
struct Struct {
a: i64,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print struct_padded_at_end
// check:$5 = {x = {22, 23}, y = {24, 25}}
+#[allow(unused_variable)];
+
struct NoPadding1 {
x: [u32, ..3],
y: i32,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print *t0
+// check:$1 = 1
+// debugger:print *t1
+// check:$2 = 2.5
+// debugger:print ret
+// check:$3 = {{1, 2.5}, {2.5, 1}}
+// debugger:continue
+
+// debugger:finish
+// debugger:print *t0
+// check:$4 = 3.5
+// debugger:print *t1
+// check:$5 = 4
+// debugger:print ret
+// check:$6 = {{3.5, 4}, {4, 3.5}}
+// debugger:continue
+
+// debugger:finish
+// debugger:print *t0
+// check:$7 = 5
+// debugger:print *t1
+// check:$8 = {a = 6, b = 7.5}
+// debugger:print ret
+// check:$9 = {{5, {a = 6, b = 7.5}}, {{a = 6, b = 7.5}, 5}}
+// debugger:continue
+
+#[deriving(Clone)]
+struct Struct {
+ a: int,
+ b: float
+}
+
+fn dup_tup<T0: Clone, T1: Clone>(t0: &T0, t1: &T1) -> ((T0, T1), (T1, T0)) {
+ let ret = ((t0.clone(), t1.clone()), (t1.clone(), t0.clone()));
+ zzz();
+ ret
+}
+
+fn main() {
+
+ let _ = dup_tup(&1, &2.5);
+ let _ = dup_tup(&3.5, &4_u16);
+ let _ = dup_tup(&5, &Struct { a: 6, b: 7.5 });
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print x
+// check:$1 = -1
+// debugger:print y
+// check:$2 = 1
+// debugger:continue
+
+// debugger:finish
+// debugger:print x
+// check:$3 = -1
+// debugger:print y
+// check:$4 = 2.5
+// debugger:continue
+
+// debugger:finish
+// debugger:print x
+// check:$5 = -2.5
+// debugger:print y
+// check:$6 = 1
+// debugger:continue
+
+// debugger:finish
+// debugger:print x
+// check:$7 = -2.5
+// debugger:print y
+// check:$8 = 2.5
+// debugger:continue
+
+fn outer<TA: Clone>(a: TA) {
+ inner(a.clone(), 1);
+ inner(a.clone(), 2.5);
+
+ fn inner<TX, TY>(x: TX, y: TY) {
+ zzz();
+ }
+}
+
+fn main() {
+ outer(-1);
+ outer(-2.5);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print/d arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 1234.5}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 1234.5}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 1234.5}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10.5
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = -1}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12.5
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = -1}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print *arg2
+// check:$18 = {-14, 14}
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = -1}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print *arg2
+// check:$21 = {-16, 16.5}
+// debugger:continue
+
+struct Struct<T> {
+ x: T
+}
+
+impl<T1> Struct<T1> {
+
+ fn self_by_ref<T2>(&self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_by_val<T2>(self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_owned<T2>(~self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_managed<T2>(@self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+}
+
+fn main() {
+ let stack = Struct { x: (8888_u32, -8888_i32) };
+ let _ = stack.self_by_ref(-1, -2_i8);
+ let _ = stack.self_by_val(-3, -4_i16);
+
+ let owned = ~Struct { x: 1234.5 };
+ let _ = owned.self_by_ref(-5, -6_i32);
+ let _ = owned.self_by_val(-7, -8_i64);
+ let _ = owned.self_owned(-9, -10.5_f32);
+
+ let managed = @Struct { x: -1_i16 };
+ let _ = managed.self_by_ref(-11, -12.5_f64);
+ let _ = managed.self_by_val(-13, &(-14, 14));
+ let _ = managed.self_managed(-15, &(-16, 16.5));
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STRUCT
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1
+// debugger:print arg2
+// check:$2 = 2
+// debugger:continue
+
+// ENUM
+// debugger:finish
+// debugger:print arg1
+// check:$3 = -3
+// debugger:print arg2
+// check:$4 = 4.5
+// debugger:print arg3
+// check:$5 = 5
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+impl Struct {
+
+ fn static_method<T1, T2>(arg1: T1, arg2: T2) -> int {
+ zzz();
+ return 0;
+ }
+}
+
+enum Enum {
+ Variant1 { x: int },
+ Variant2,
+ Variant3(float, int, char),
+}
+
+impl Enum {
+
+ fn static_method<T1, T2, T3>(arg1: T1, arg2: T2, arg3: T3) -> int {
+ zzz();
+ return 1;
+ }
+}
+
+fn main() {
+ Struct::static_method(1, 2);
+ Enum::static_method(-3, 4.5, 5);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print union on
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print case1
+// check:$1 = {{Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {Case1, a = 0, b = 2088533116, c = 2088533116}, {Case1, a = 0, b = 8970181431921507452}}
+
+// debugger:print case2
+// check:$2 = {{Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {Case2, a = 0, b = 286331153, c = 286331153}, {Case2, a = 0, b = 1229782938247303441}}
+
+// debugger:print case3
+// check:$3 = {{Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {Case3, a = 0, b = 1499027801, c = 1499027801}, {Case3, a = 0, b = 6438275382588823897}}
+
+// debugger:print univariant
+// check:$4 = {a = -1}
+
+// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
+// substituted with something of size `xx` bits and the same alignment as an integer type of the
+// same size.
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular<T16, T32, T64> {
+ Case1 { a: T64, b: T16, c: T16, d: T16, e: T16},
+ Case2 { a: T64, b: T32, c: T32},
+ Case3 { a: T64, b: T64 }
+}
+
+enum Univariant<T> {
+ TheOnlyCase { a: T }
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let case1: Regular<u16, u32, i64> = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 };
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let case2: Regular<i16, u32, i64> = Case2 { a: 0, b: 286331153, c: 286331153 };
+
+ // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+ // 0b01011001010110010101100101011001 = 1499027801
+ // 0b0101100101011001 = 22873
+ // 0b01011001 = 89
+ let case3: Regular<u16, i32, u64> = Case3 { a: 0, b: 6438275382588823897 };
+
+ let univariant = TheOnlyCase { a: -1 };
+
+ zzz();
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print int_int
+// check:$1 = {key = 0, value = 1}
+// debugger:print int_float
+// check:$2 = {key = 2, value = 3.5}
+// debugger:print float_int
+// check:$3 = {key = 4.5, value = 5}
+// debugger:print float_int_float
+// check:$4 = {key = 6.5, value = {key = 7, value = 8.5}}
+
+struct AGenericStruct<TKey, TValue> {
+ key: TKey,
+ value: TValue
+}
+
+fn main() {
+
+ let int_int = AGenericStruct { key: 0, value: 1 };
+ let int_float = AGenericStruct { key: 2, value: 3.5 };
+ let float_int = AGenericStruct { key: 4.5, value: 5 };
+ let float_int_float = AGenericStruct { key: 6.5, value: AGenericStruct { key: 7, value: 8.5 } };
+
+ zzz();
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1000
+// debugger:print *arg2
+// check:$2 = {1, 2.5}
+// debugger:continue
+
+// debugger:finish
+// debugger:print arg1
+// check:$3 = 2000
+// debugger:print *arg2
+// check:$4 = {3.5, {4, 5, 6}}
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+trait Trait<T1> {
+ fn generic_static_default_method<T2>(arg1: int, arg2: &(T1, T2)) -> int {
+ zzz();
+ arg1
+ }
+}
+
+impl<T> Trait<T> for Struct;
+
+fn main() {
+
+ // Is this really how to use these?
+ Trait::generic_static_default_method::<int, Struct, float>(1000, &(1, 2.5));
+ Trait::generic_static_default_method::<float, Struct, (int, int, int)>(2000, &(3.5, (4, 5, 6)));
+
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print union on
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print case1
+// check:$1 = {{Case1, 0, 31868, 31868, 31868, 31868}, {Case1, 0, 2088533116, 2088533116}, {Case1, 0, 8970181431921507452}}
+
+// debugger:print case2
+// check:$2 = {{Case2, 0, 4369, 4369, 4369, 4369}, {Case2, 0, 286331153, 286331153}, {Case2, 0, 1229782938247303441}}
+
+// debugger:print case3
+// check:$3 = {{Case3, 0, 22873, 22873, 22873, 22873}, {Case3, 0, 1499027801, 1499027801}, {Case3, 0, 6438275382588823897}}
+
+// debugger:print univariant
+// check:$4 = {-1}
+
+
+// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
+// substituted with something of size `xx` bits and the same alignment as an integer type of the
+// same size.
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular<T16, T32, T64> {
+ Case1(T64, T16, T16, T16, T16),
+ Case2(T64, T32, T32),
+ Case3(T64, T64)
+}
+
+enum Univariant<T64> {
+ TheOnlyCase(T64)
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let case1: Regular<u16, u32, u64> = Case1(0_u64, 31868_u16, 31868_u16, 31868_u16, 31868_u16);
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let case2: Regular<i16, i32, i64> = Case2(0_i64, 286331153_i32, 286331153_i32);
+
+ // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+ // 0b01011001010110010101100101011001 = 1499027801
+ // 0b0101100101011001 = 22873
+ // 0b01011001 = 89
+ let case3: Regular<i16, i32, i64> = Case3(0_i64, 6438275382588823897_i64);
+
+ let univariant = TheOnlyCase(-1_i64);
+
+ zzz();
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z debug-info
+// debugger:run
+
+// Nothing to do here really, just make sure it compiles. See issue #8513.
+fn main() {
+ let _ = ||();
+ let _ = range(1u,3).map(|_| 5);
+}
+
// debugger:print univariant->val
// check:$3 = {-9747455}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print unique->val.elements[3]->val
// check:$4 = 13
+#[allow(unused_variable)];
+
fn main() {
let unique: ~[@i64] = ~[@10, @11, @12, @13];
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print managed_within_unique.val->y->val
// check:$3 = -4
+#[allow(unused_variable)];
+
struct ContainsManaged
{
x: int,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+enum Enum {
+ Variant1 { x: u16, y: u16 },
+ Variant2 (u32)
+}
+
+impl Enum {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Variant2(117901063);
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Variant1{ x: 1799, y: 1799 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Variant2(117901063);
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 1234.5}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 1234.5}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 1234.5}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = -1}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = -1}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = -1}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct<T> {
+ x: T
+}
+
+impl<T> Struct<T> {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Struct { x: (8888_u32, -8888_i32) };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 1234.5 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: -1_i16 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 100}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 100}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 200}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 200}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 200}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 300}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 300}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 300}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+impl Struct {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Struct { x: 100 };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 200 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: 300 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 100}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 100}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 200}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 200}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 200}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 300}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 300}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 300}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int;
+ fn self_by_val(self, arg1: int, arg2: int) -> int;
+ fn self_owned(~self, arg1: int, arg2: int) -> int;
+ fn self_managed(@self, arg1: int, arg2: int) -> int;
+}
+
+impl Trait for Struct {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Struct { x: 100 };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 200 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: 300 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {100, -100.5}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {100, -100.5}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {200, -200.5}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {200, -200.5}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {200, -200.5}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {300, -300.5}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {300, -300.5}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {300, -300.5}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct TupleStruct(int, float);
+
+impl TupleStruct {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = TupleStruct(100, -100.5);
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~TupleStruct(200, -200.5);
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @TupleStruct(300, -300.5);
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
// debugger:print abc
// check:$3 = 30303
+#[allow(unused_variable)];
+
fn function_one() {
let abc = 10101;
zzz();
// debugger:print c
// check:$3 = 30303
+#[allow(unused_variable)];
+
fn function_one() {
let a = 10101;
zzz();
// debugger:print second
// check:$2 = {<No data fields>}
+#[allow(unused_variable)];
+
enum ANilEnum {}
enum AnotherNilEnum {}
}
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-// xfail-test broken in newrt?
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:print full
// check:$3 = {454545, 0x87654321, 9988}
-// debugger:print empty
-// check:$4 = {0, 0x0, 0}
+// debugger:print empty->discr
+// check:$4 = (int *) 0x0
// debugger:print droid
// check:$5 = {id = 675675, range = 10000001, internals = 0x43218765}
-// debugger:print void_droid
-// check:$6 = {id = 0, range = 0, internals = 0x0}
+// debugger:print void_droid->internals
+// check:$6 = (int *) 0x0
+// debugger:continue
// If a struct has exactly two variants, one of them is empty, and the other one
// contains a non-nullable pointer, then this value is used as the discriminator.
// The test cases in this file make sure that something readable is generated for
// this kind of types.
+// Unfortunately (for these test cases) the content of the non-discriminant fields
+// in the null-case is not defined. So we just read the discriminator field in
+// this case (by casting the value to a memory-equivalent struct).
enum MoreFields<'self> {
Full(u32, &'self int, i16),
Empty
}
+struct MoreFieldsRepr<'self> {
+ a: u32,
+ discr: &'self int,
+ b: i16
+}
+
enum NamedFields<'self> {
Droid { id: i32, range: i64, internals: &'self int },
Void
}
+struct NamedFieldsRepr<'self> {
+ id: i32,
+ range: i64,
+ internals: &'self int
+}
+
fn main() {
let some: Option<&u32> = Some(unsafe { std::cast::transmute(0x12345678) });
let full = Full(454545, unsafe { std::cast::transmute(0x87654321) }, 9988);
let int_val = 0;
- let mut empty = Full(0, &int_val, 0);
- empty = Empty;
+ let empty: &MoreFieldsRepr = unsafe { std::cast::transmute(&Empty) };
- let droid = Droid { id: 675675, range: 10000001, internals: unsafe { std::cast::transmute(0x43218765) } };
+ let droid = Droid {
+ id: 675675,
+ range: 10000001,
+ internals: unsafe { std::cast::transmute(0x43218765) }
+ };
- let mut void_droid = Droid { id: 0, range: 0, internals: &int_val };
- void_droid = Void;
+ let void_droid: &NamedFieldsRepr = unsafe { std::cast::transmute(&Void) };
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print deeplyNested
// check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}}
+#[allow(unused_variable)];
+
#[packed]
struct Packed {
x: i16,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print sizeof(packedInPacked)
// check:$6 = 40
+#[allow(unused_variable)];
+
#[packed]
struct Packed {
x: i16,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 100}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 100}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 200}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 200}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 200}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 300}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 300}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 300}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+impl Trait for Struct;
+
+fn main() {
+ let stack = Struct { x: 100 };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 200 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: 300 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 987}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print/d arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 987}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 879}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 879}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 879}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10.5
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 897}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12.5
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 897}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print *arg2
+// check:$18 = {-14, 14}
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 897}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print *arg2
+// check:$21 = {-16, 16.5}
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+
+ fn self_by_ref<T>(&self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_by_val<T>(self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_owned<T>(~self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_managed<T>(@self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+}
+
+impl Trait for Struct;
+
+fn main() {
+ let stack = Struct { x: 987 };
+ let _ = stack.self_by_ref(-1, -2_i8);
+ let _ = stack.self_by_val(-3, -4_i16);
+
+ let owned = ~Struct { x: 879 };
+ let _ = owned.self_by_ref(-5, -6_i32);
+ let _ = owned.self_by_val(-7, -8_i64);
+ let _ = owned.self_owned(-9, -10.5_f32);
+
+ let managed = @Struct { x: 897 };
+ let _ = managed.self_by_ref(-11, -12.5_f64);
+ let _ = managed.self_by_val(-13, &(-14, 14));
+ let _ = managed.self_managed(-15, &(-16, 16.5));
+}
+
+fn zzz() {()}
// debugger:print padding_at_end
// check:$6 = {x = -10014, y = 10015}
+#[allow(unused_variable)];
struct NoPadding16 {
x: u16,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print paddingAtEnd
// check:$7 = {15, 16}
+#[allow(unused_variable)];
fn main() {
let noPadding8: (i8, u8) = (-100, 100);
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STRUCT
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1
+// debugger:print arg2
+// check:$2 = 2
+// debugger:continue
+
+// ENUM
+// debugger:finish
+// debugger:print arg1
+// check:$3 = -3
+// debugger:print arg2
+// check:$4 = 4.5
+// debugger:print arg3
+// check:$5 = 5
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+impl Struct {
+
+ fn static_method(arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+enum Enum {
+ Variant1 { x: int },
+ Variant2,
+ Variant3(float, int, char),
+}
+
+impl Enum {
+
+ fn static_method(arg1: int, arg2: float, arg3: uint) -> int {
+ zzz();
+ arg1
+ }
+}
+
+fn main() {
+ Struct::static_method(1, 2);
+ Enum::static_method(-3, 4.5, 5);
+}
+
+fn zzz() {()}
// debugger:print univariant
// check:$3 = {{x = 123, y = 456, z = 789}}
+#[allow(unused_variable)];
+
struct Struct {
x: u32,
y: i32,
// debugger:print padding_at_end_parent
// check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}}
+#[allow(unused_variable)];
struct Simple {
x: i32
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print univariant
// check:$4 = {a = -1}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print nested
// check:$4 = {a = {a = {x = 7890, y = 9870}}}
+#[allow(unused_variable)];
+
struct NoDestructor {
x: i32,
y: i64
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1000
+// debugger:print arg2
+// check:$2 = 0.5
+// debugger:continue
+
+// debugger:finish
+// debugger:print arg1
+// check:$3 = 2000
+// debugger:print *arg2
+// check:$4 = {1, 2, 3}
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+ fn generic_static_default_method<T>(arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+}
+
+impl Trait for Struct;
+
+fn main() {
+
+ // Is this really how to use these?
+ Trait::generic_static_default_method::<Struct, float>(1000, 0.5);
+ Trait::generic_static_default_method::<Struct, &(int, int, int)>(2000, &(1, 2, 3));
+
+}
+
+fn zzz() {()}
// debugger:print mixed_padding
// check:$10 = {x = {{40, 41, 42}, {43, 44}}, y = {45, 46, 47, 48}}
+#[allow(unused_variable)];
+
struct NoPadding1 {
x: (i32, i32),
y: i32,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print padding_at_end2
// check:$7 = {{21, 22}, 23}
+#[allow(unused_variable)];
+
fn main() {
let no_padding1: ((u32, u32), u32, u32) = ((0, 1), 2, 3);
let no_padding2: (u32, (u32, u32), u32) = (4, (5, 6), 7);
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print pretty off
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print no_padding16
+// check:$1 = {10000, -10001}
+
+// debugger:print no_padding32
+// check:$2 = {-10002, -10003.5, 10004}
+
+// debugger:print no_padding64
+// check:$3 = {-10005.5, 10006, 10007}
+
+// debugger:print no_padding163264
+// check:$4 = {-10008, 10009, 10010, 10011}
+
+// debugger:print internal_padding
+// check:$5 = {10012, -10013}
+
+// debugger:print padding_at_end
+// check:$6 = {-10014, 10015}
+
+
+// This test case mainly makes sure that no field names are generated for tuple structs (as opposed
+// to all fields having the name "__field__"). Otherwise they are handled the same a normal structs.
+
+struct NoPadding16(u16, i16);
+struct NoPadding32(i32, f32, u32);
+struct NoPadding64(f64, i64, u64);
+struct NoPadding163264(i16, u16, i32, u64);
+struct InternalPadding(u16, i64);
+struct PaddingAtEnd(i64, u16);
+
+fn main() {
+ let no_padding16 = NoPadding16(10000, -10001);
+ let no_padding32 = NoPadding32(-10002, -10003.5, 10004);
+ let no_padding64 = NoPadding64(-10005.5, 10006, 10007);
+ let no_padding163264 = NoPadding163264(-10008, 10009, 10010, 10011);
+
+ let internal_padding = InternalPadding(10012, -10013);
+ let padding_at_end = PaddingAtEnd(-10014, 10015);
+
+ zzz();
+}
+
+fn zzz() {()}
// debugger:print univariant
// check:$4 = {-1}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *univariant
// check:$3 = {123234}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print padded_struct.data_ptr[1]
// check:$13 = {x = 13, y = 14, z = 15}
+#[allow(unused_variable)];
+
struct AStruct {
x: i16,
y: i32,
// debugger:print a
// check:$1 = {1, 2, 3}
+#[allow(unused_variable)];
+
fn main() {
let a = [1, 2, 3];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn blk1(b: &fn()) -> @fn() { return || { }; }
+fn blk1(_b: &fn()) -> @fn() { return || { }; }
fn test1() { (do blk1 { info!("hi"); })(); }
fn id(f: &fn() -> int) -> int { f() }
-fn wsucc(n: int) -> int { (do id || { 1 }) - 0 }
+fn wsucc(_n: int) -> int { (do id || { 1 }) - 0 }
fn main() { }
// pp-exact
-fn from_foreign_fn(x: extern "Rust" fn()) { }
-fn from_stack_closure(x: &fn()) { }
-fn from_box_closure(x: @fn()) { }
-fn from_unique_closure(x: ~fn()) { }
+fn from_foreign_fn(_x: extern "Rust" fn()) { }
+fn from_stack_closure(_x: &fn()) { }
+fn from_box_closure(_x: @fn()) { }
+fn from_unique_closure(_x: ~fn()) { }
fn main() { }
// pp-exact
-fn f(v: &[int]) {
+fn f(v: &[int]) -> int {
let mut n = 0;
for e in v.iter() {
n = *e; // This comment once triggered pretty printer bug
}
+
+ n
}
fn main() {
let x = Some(3);
- let y =
+ let _y =
match x {
Some(_) =>
- ~"some" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" +
- ~"very" + ~"very" + ~"very" + ~"long" + ~"string",
+ ~"some" + "very" + "very" + "very" + "very" + "very" + "very" +
+ "very" + "very" + "long" + "string",
None => ~"none"
};
}
fn main() {
let x = Some(3);
- let y = match x { Some(_) => ~"some(_)", None => ~"none" };
+ let _y = match x { Some(_) => ~"some(_)", None => ~"none" };
}
fn main() {
struct Foo2;
struct Bar2(int, int, int);
- let a = Bar(5, 5);
- let b = Foo;
+ let _a = Bar(5, 5);
+ let _b = Foo;
}
// Testing that comments are correctly interleaved
// pp-exact:vec-comments.pp
fn main() {
- let v1 =
+ let _v1 =
~[
// Comment
0,
1,
// Comment
2];
- let v2 =
+ let _v2 =
~[0, // Comment
1, // Comment
2]; // Comment
- let v3 =
+ let _v3 =
~[
/* Comment */
0,
1,
/* Comment */
2];
- let v4 =
+ let _v4 =
~[0, /* Comment */
1, /* Comment */
2]; /* Comment */
// Testing that comments are correctly interleaved
// pp-exact:vec-comments.pp
fn main() {
- let v1 =
+ let _v1 =
~[
// Comment
0,
1,
// Comment
2];
- let v2 =
+ let _v2 =
~[0, // Comment
1, // Comment
2]; // Comment
- let v3 =
+ let _v3 =
~[
/* Comment */
0,
1,
/* Comment */
2];
- let v4 =
+ let _v4 =
~[0, /* Comment */
1, /* Comment */
2]; /* Comment */
// pp-exact:vec-type.pp
-fn f1(x: ~[int]) { }
+fn f1(_x: ~[int]) { }
fn g1() { f1(~[1, 2, 3]); }
// pp-exact:vec-type.pp
-fn f1(x: ~[int]) { }
+fn f1(_x: ~[int]) { }
fn g1() { f1(~[1, 2, 3]); }
// except according to those terms.
// error-pattern:meep
-fn f(a: int, b: int, c: @int) { fail!("moop"); }
+fn f(_a: int, _b: int, _c: @int) { fail!("moop"); }
fn main() { f(1, fail!("meep"), @42); }
let c = @mut b;
// this should freeze `a` only
- let x: &mut [int] = c[0];
+ let _x: &mut [int] = c[0];
// hence this should fail
a[0] = a[0];
fn main() {
let x = @mut S { x: 3 };
- let y: &S = x;
+ let _y: &S = x;
let z = x;
z.x = 5;
}
fn main() {
let x = @mut 3;
- let y: &mut int = x;
+ let _y: &mut int = x;
let z = x;
*z = 5;
}
}
}
-fn it_takes_two(f: &Foo, g: &mut Foo) {
+fn it_takes_two(_f: &Foo, _g: &mut Foo) {
}
fn main() {
pub fn main()
{
let a = @mut 3;
- let b = &*a; // freezes a
+ let _b = &*a; // freezes a
add1(a);
}
pub fn main()
{
let a = @mut 3;
- let b = &mut *a; // freezes a
+ let _b = &mut *a; // freezes a
add1(a);
}
port: port_id,
}
-fn send<T:Send>(ch: chan_t<T>, data: T) { fail!(); }
+fn send<T:Send>(_ch: chan_t<T>, _data: T) { fail!(); }
fn main() { fail!("quux"); }
// error-pattern:test
fn main() {
- let i: int = fail!("test");
+ let _i: int = fail!("test");
}
// error-pattern:attempted to divide by zero
fn main() {
let y = 0;
- let z = 1 / y;
+ let _z = 1 / y;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+
//error-pattern:One
fn main() {
fail!("One");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
// error-pattern:wooooo
fn main() {
- let mut a = 1; if 1 == 1 { a = 2; } fail!(~"woooo" + "o");
+ let mut a = 1;
+ if 1 == 1 { a = 2; }
+ fail!(~"woooo" + "o");
}
// error-pattern:explicit failure
-fn main() { let x = if false { 0 } else if true { fail!() } else { 10 }; }
+fn main() { let _x = if false { 0 } else if true { fail!() } else { 10 }; }
// error-pattern:explicit failure
-fn main() { let x = match true { false => { 0 } true => { fail!() } }; }
+fn main() { let _x = match true { false => { 0 } true => { fail!() } }; }
fn count(n: uint) -> uint {
unsafe {
- task::yield();
+ task::deschedule();
rustrt::rust_dbg_call(cb, n)
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+
// error-pattern:explicit failure
// Don't double free the string
extern mod extra;
fn foo() -> e<int> {fail!();}
fn main() {
- let f = foo();
+ let _f = foo();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
// error-pattern:so long
fn main() {
let mut x = ~[];
// error-pattern:beep boop
+#[allow(unused_variable)];
+
struct Point { x: int, y: int }
fn main() {
fn main() {
let (p, _c) = comm::stream::<()>();
task::spawn(|| child() );
- task::yield();
+ task::deschedule();
}
// error-pattern:explicit failure
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
fn foo(s: ~str) { }
fn main() {
// error-pattern:attempted remainder with a divisor of zero
fn main() {
let y = 0;
- let z = 1 % y;
+ let _z = 1 % y;
}
// as a _|_-typed thing, not a str-typed thing
// error-pattern:bye
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
struct T { t: ~str }
-fn main() { let pth = fail!("bye"); let rs: T = T {t: pth}; }
+fn main() {
+ let pth = fail!("bye");
+ let _rs: T = T {t: pth};
+}
fn main() {
error!(~"whatever");
do task::spawn {
- let i = r(5);
+ let _i = r(5);
};
fail!();
}
use std::task;
fn goodfail() {
- task::yield();
+ task::deschedule();
fail!("goodfail");
}
// error-pattern:Ensure that the child task runs by failing
-use std::str;
use std::task;
fn main() {
// error-pattern:fail
fn main() {
- let a = @0;
+ let _a = @0;
assert!(false);
}
// error-pattern:fail
-fn f(a: @int) {
+fn f(_a: @int) {
fail!();
}
fn f() -> @int { fail!(); }
fn main() {
- let a: @int = f();
+ let _a: @int = f();
}
// error-pattern:fail
fn main() {
- let a: @int = {
+ let _a: @int = {
fail!();
};
}
fn b() { fail!(); }
fn main() {
- let x = ~[0];
+ let _x = ~[0];
a();
- let y = ~[0];
+ let _y = ~[0];
b();
}
// error-pattern:fail
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
fn x(it: &fn(int)) {
fail!();
it(0);
// error-pattern:fail
fn x(it: &fn(int)) {
- let a = @0;
+ let _a = @0;
it(1);
}
let mush = food + cheese;
let cheese = cheese.clone();
let f: &fn() = || {
- let chew = mush + cheese;
+ let _chew = mush + cheese;
fail!("so yummy")
};
f();
// error-pattern:fail
fn main() {
- let count = @mut 0u;
+ let _count = @mut 0u;
let mut map = std::hashmap::HashMap::new();
let mut arr = ~[];
- for i in range(0u, 10u) {
+ for _i in range(0u, 10u) {
arr.push(@~"key stuff");
map.insert(arr.clone(), arr + &[@~"value stuff"]);
if arr.len() == 5 {
// error-pattern:fail
fn main() {
- let a = @0;
+ let _a = @0;
{
- let b = @0;
+ let _b = @0;
{
fail!();
}
}
fn partial() {
- let x = @f();
+ let _x = @f();
}
fn main() {
}
fn partial() {
- let x = ~f();
+ let _x = ~f();
}
fn main() {
}
fn partial() {
- let x = ~[~[0], f(), ~[0]];
+ let _x = ~[~[0], f(), ~[0]];
}
fn main() {
struct Blk { node: ~[int] }
fn main() {
- let blk = Blk {
+ let _blk = Blk {
node: build()
};
}
struct Blk { node: ~[int], span: ~[int] }
fn main() {
- let blk = Blk {
+ let _blk = Blk {
node: build1(),
span: build2()
};
fn main() {
@0;
- let r = r(0);
+ let _r = r(0);
}
// error-pattern:fail
fn f() {
- let a = @0;
+ let _a = @0;
fail!();
}
fn g() {
- let b = @0;
+ let _b = @0;
f();
}
fn main() {
- let a = @0;
+ let _a = @0;
g();
}
}
fn main() {
- let lss = (fold_local(), 0);
+ let _lss = (fold_local(), 0);
}
}
fn main() {
- let lss = (fold_local(), fold_remote());
+ let _lss = (fold_local(), fold_remote());
}
fn main() {
f();
- let a = @0;
+ let _a = @0;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(while_true)];
+
// error-pattern:quux
-fn main() { let x: int = { while true { fail!("quux"); } ; 8 } ; }
+fn main() { let _x: int = { while true { fail!("quux"); } ; 8 } ; }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(while_true)];
+
// error-pattern:giraffe
fn main() {
fail!({ while true { fail!("giraffe") }; "clandestine" });
+++ /dev/null
-// Copyright 2012 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.
-
-// In this case, the code should compile but
-// the assert should fail at runtime
-// error-pattern:assertion failed
-extern mod extra;
-use std::vec::{same_length, zip};
-
-fn enum_chars(start: u8, end: u8) -> ~[char] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i as char); i += 1 as u8; }
- return r;
-}
-
-fn enum_uints(start: uint, end: uint) -> ~[uint] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i); i += 1; }
- return r;
-}
-
-fn main() {
- let a = 'a' as u8;
- let j = 'j' as u8;
- let k = 1;
- let l = 9;
- let chars = enum_chars(a, j);
- let ints = enum_uints(k, l);
-
- assert!(same_length(chars, ints));
- let ps = zip(chars, ints);
- fail!("the impossible happened");
-}
fn main() {
- let ext_cx = mk_ctxt();
- let s = quote_expr!(__s);
- let e = quote_expr!(__e);
- let f = quote_expr!($s.foo {|__e| $e});
+ let cx = mk_ctxt();
+ let s = quote_expr!(cx, __s);
+ let e = quote_expr!(cx, __e);
+ let f = quote_expr!(cx, $s.foo {|__e| $e});
log(error, pprust::expr_to_str(f));
}
}
fn main() {
- let ext_cx = mk_ctxt();
+ let cx = mk_ctxt();
- let abc = quote_expr!(23);
+ let abc = quote_expr!(cx, 23);
check_pp(ext_cx, abc, pprust::print_expr, ~"23");
- let ty = quote_ty!(int);
+ let ty = quote_ty!(cx, int);
check_pp(ext_cx, ty, pprust::print_type, ~"int");
- let item = quote_item!(static x : int = 10;).get();
+ let item = quote_item!(cx, static x : int = 10;).get();
check_pp(ext_cx, item, pprust::print_item, ~"static x: int = 10;");
- let stmt = quote_stmt!(let x = 20;);
+ let stmt = quote_stmt!(cx, let x = 20;);
check_pp(ext_cx, *stmt, pprust::print_stmt, ~"let x = 20;");
- let pat = quote_pat!(Some(_));
+ let pat = quote_pat!(cx, Some(_));
check_pp(ext_cx, pat, pprust::print_pat, ~"Some(_)");
}
use syntax::ext::base::ExtCtxt;
-fn syntax_extension(ext_cx: @ExtCtxt) {
- let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(1 + 2);
- let p_toks : ~[syntax::ast::token_tree] = quote_tokens!((x, 1 .. 4, *));
+fn syntax_extension(cx: @ExtCtxt) {
+ let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, 1 + 2);
+ let p_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, (x, 1 .. 4, *));
- let a: @syntax::ast::expr = quote_expr!(1 + 2);
- let _b: Option<@syntax::ast::item> = quote_item!( static foo : int = $e_toks; );
- let _c: @syntax::ast::pat = quote_pat!( (x, 1 .. 4, *) );
- let _d: @syntax::ast::stmt = quote_stmt!( let x = $a; );
- let _e: @syntax::ast::expr = quote_expr!( match foo { $p_toks => 10 } );
+ let a: @syntax::ast::expr = quote_expr!(cx, 1 + 2);
+ let _b: Option<@syntax::ast::item> = quote_item!(cx, static foo : int = $e_toks; );
+ let _c: @syntax::ast::pat = quote_pat!(cx, (x, 1 .. 4, *) );
+ let _d: @syntax::ast::stmt = quote_stmt!(cx, let x = $a; );
+ let _e: @syntax::ast::expr = quote_expr!(cx, match foo { $p_toks => 10 } );
}
fn main() {
use anonexternmod::*;
+#[fixed_stack_segment]
pub fn main() {
unsafe {
rust_get_test_int();
fn rust_get_test_int() -> libc::intptr_t;
}
+#[fixed_stack_segment]
pub fn main() {
unsafe {
let _ = rust_get_test_int();
pub fn main() {
let mut a = X {x: 1};
let mut b = 2;
- let mut c = 3;
+ let c = 3;
assert_eq!(f1(&mut a, &mut b, c), 6);
assert_eq!(a.x, 0);
assert_eq!(b, 10);
- assert_eq!(f2(a.x, |x| a.x = 50), 0);
+ assert_eq!(f2(a.x, |_| a.x = 50), 0);
assert_eq!(a.x, 50);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(type_limits)];
// Unsigned integer operations
pub fn main() {
// Issue 483 - Assignment expressions result in nil
fn test_assign() {
let mut x: int;
- let mut y: () = x = 10;
+ let y: () = x = 10;
assert_eq!(x, 10);
+ assert_eq!(y, ());
let mut z = x = 11;
assert_eq!(x, 11);
+ assert_eq!(z, ());
z = x = 12;
assert_eq!(x, 12);
+ assert_eq!(z, ());
}
fn test_assign_op() {
let mut x: int = 0;
- let mut y: () = x += 10;
+ let y: () = x += 10;
assert_eq!(x, 10);
+ assert_eq!(y, ());
let mut z = x += 11;
assert_eq!(x, 21);
+ assert_eq!(z, ());
z = x += 12;
assert_eq!(x, 33);
+ assert_eq!(z, ());
}
pub fn main() { test_assign(); test_assign_op(); }
//xfail-fast
#[start]
-fn start(argc:int, argv: **u8, crate_map: *u8) -> int {
+fn start(_argc: int, _argv: **u8, _crate_map: *u8) -> int {
return 0;
}
// xfail-fast
extern mod extra;
use extra::arc;
-fn dispose(_x: arc::Arc<bool>) { unsafe { } }
+fn dispose(_x: arc::Arc<bool>) { }
pub fn main() {
let p = arc::Arc::new(true);
// Binop corner cases
-use std::libc;
-
fn test_nil() {
assert_eq!((), ());
assert!((!(() != ())));
}
fn test_class() {
- let mut q = p(1, 2);
+ let q = p(1, 2);
let mut r = p(1, 2);
unsafe {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
fn w_semi(v: ~[int]) -> int {
// the semicolon causes compiler not to
// complain about the ignored return value:
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
// Check usage and precedence of block arguments in expressions:
pub fn main() {
let v = ~[-1f, 0f, 1f, 2f, 3f];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
use std::util;
struct Ints {sum: ~int, values: ~[int]}
}
Some(_) => { }
}
+ assert_eq!(x, Some(0));
}
pub fn main() {
let x: @mut @Option<~int> = @mut @None;
match x {
- @@Some(ref y) => {
+ @@Some(ref _y) => {
// here, the refcount of `*x` is bumped so
- // `y` remains valid even if `*x` is modified.
+ // `_y` remains valid even if `*x` is modified.
*x = @None;
}
@@None => {
struct F { f: ~int }
pub fn main() {
- let mut x = @mut @F {f: ~3};
+ let x = @mut @F {f: ~3};
match x {
@@F{f: ref b_x} => {
assert_eq!(**b_x, 3);
fn switcher(x: Option<@int>) {
let mut x = x;
match x {
- Some(@y) => { y.clone(); x = None; }
- None => { }
+ Some(@y) => { y.clone(); x = None; }
+ None => { }
}
+ assert_eq!(x, None);
}
pub fn main() {
let mut y = @4;
// borrow x and y
- let mut r_x = &*x;
- let mut r_y = &*y;
+ let r_x = &*x;
+ let r_y = &*y;
let mut r = r_x;
let mut exp = 3;
info!("*r = %d, exp = %d", *r, exp);
assert_eq!(*r, exp);
+ assert_eq!(x, @5);
+ assert_eq!(y, @6);
}
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main() { let i: (@int, int) = (@10, 10); let (a, _) = i; }
+pub fn main() {
+ let i: (@int, int) = (@10, 10);
+ let (_a, _) = i;
+}
fn some_box(x: int) -> @int { return @x; }
-fn is_odd(n: int) -> bool { return true; }
+fn is_odd(_n: int) -> bool { return true; }
-fn length_is_even(vs: @int) -> bool { return true; }
+fn length_is_even(_vs: @int) -> bool { return true; }
-fn foo(acc: int, n: int) {
+fn foo(_acc: int, n: int) {
if is_odd(n) && length_is_even(some_box(1)) { error!("bloop"); }
}
fn some_box(x: int) -> @int { return @x; }
-fn is_odd(n: int) -> bool { return true; }
+fn is_odd(_n: int) -> bool { return true; }
-fn length_is_even(vs: @int) -> bool { return true; }
+fn length_is_even(_vs: @int) -> bool { return true; }
-fn foo(acc: int, n: int) {
+fn foo(_acc: int, n: int) {
if is_odd(n) || length_is_even(some_box(1)) { error!("bloop"); }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
pub fn main() {
let mut i = 0;
while i < 20 { i += 1; if i == 10 { break; } }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::libc;
-
mod rustrt {
use std::libc;
}
pub fn main() {
- unsafe {
- let _foo = rustrt::rust_get_test_int;
- }
+ let _foo = rustrt::rust_get_test_int;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
mod libc {
+ use std::libc::{c_char, c_long, c_longlong};
+
#[abi = "cdecl"]
#[nolink]
extern {
- pub fn atol(x: *u8) -> int;
- pub fn atoll(x: *u8) -> i64;
+ pub fn atol(x: *c_char) -> c_long;
+ pub fn atoll(x: *c_char) -> c_longlong;
}
}
+#[fixed_stack_segment]
fn atol(s: ~str) -> int {
- s.to_c_str().with_ref(|x| unsafe { libc::atol(x as *u8) })
+ s.with_c_str(|x| unsafe { libc::atol(x) as int })
}
+#[fixed_stack_segment]
fn atoll(s: ~str) -> i64 {
- s.to_c_str().with_ref(|x| unsafe { libc::atoll(x as *u8) })
+ s.with_c_str(|x| unsafe { libc::atoll(x) as i64 })
}
pub fn main() {
- unsafe {
- assert_eq!(atol(~"1024") * 10, atol(~"10240"));
- assert!((atoll(~"11111111111111111") * 10i64)
- == atoll(~"111111111111111110"));
- }
+ assert_eq!(atol(~"1024") * 10, atol(~"10240"));
+ assert!((atoll(~"11111111111111111") * 10) == atoll(~"111111111111111110"));
}
// course preferable, as the value itself is
// irrelevant).
-use std::comm::*;
use std::task;
fn foo(x: ()) -> Port<()> {
pub fn main() {
//let bt0 = sys::rusti::frame_address(1u32);
//info!("%?", bt0);
- do cci_iter_lib::iter(~[1, 2, 3]) |i| {
+ do cci_iter_lib::iter([1, 2, 3]) |i| {
printf!("%d", *i);
//assert!(bt0 == sys::rusti::frame_address(2u32));
}
use std::task;
-fn child2(s: ~str) { }
+fn child2(_s: ~str) { }
pub fn main() {
- let x = task::spawn(|| child2(~"hi"));
+ let _x = task::spawn(|| child2(~"hi"));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
-
trait noisy {
fn speak(&self) -> int;
}
fn annoy_neighbors(critter: @noisy) {
- for i in range(0u, 10) { critter.speak(); }
+ for _i in range(0u, 10) { critter.speak(); }
}
pub fn main() {
// xfail-fast
use std::cmp;
-use std::int;
-use std::uint;
enum cat_type { tuxedo, tabby, tortoiseshell }
extern mod cci_class_trait;
use cci_class_trait::animals::*;
-use std::uint;
-
struct cat {
priv meows: uint,
// xfail-fast
-use std::uint;
-
trait noisy {
fn speak(&mut self);
}
pub fn main() {
let mut nyan : cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
nyan.speak();
pub fn main() {
let mut nyan: cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
nyan.speak();
impl ToStr for cat {
fn to_str(&self) -> ~str {
- // FIXME #5384: this unsafe block is to work around purity
- unsafe {
- self.name.clone()
- }
+ self.name.clone()
}
}
}
pub fn main() {
- let mut nyan : @ToStr = @cat(0u, 2, ~"nyan") as @ToStr;
+ let nyan : @ToStr = @cat(0u, 2, ~"nyan") as @ToStr;
print_out(nyan, ~"nyan");
}
}
pub fn main() {
- let nyan = cat(~"nyan");
+ let _nyan = cat(~"nyan");
}
pub fn main() {
- let mut _nyan : cat<int> = cat::<int>(52u, 99);
+ let _nyan : cat<int> = cat::<int>(52u, 99);
// let mut kitty = cat(1000u, 2);
}
extern mod cci_class_4;
use cci_class_4::kitties::*;
-use std::uint;
-
pub fn main() {
let mut nyan = cat(0u, 2, ~"nyan");
nyan.eat();
pub fn main() {
let mut nyan : cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
nyan.speak();
}
pub fn main() {
- let mut nyan : cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let nyan : cat = cat(52u, 99);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
}
// xfail-win32
-use std::result;
use std::task;
fn adder(x: @int, y: @int) -> int { return *x + *y; }
}
pub fn main() {
- let mut lincoln = SpeechMaker {speeches: 22};
+ let lincoln = SpeechMaker {speeches: 22};
assert_eq!(foo(&const lincoln), 55);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::task;
pub fn main() {
let (p, ch) = stream();
- let t = task::spawn(|| child(&ch) );
+ let _t = task::spawn(|| child(&ch) );
let y = p.recv();
error!("received");
error!(y);
fn nothing() { }
-fn putstr(s: ~str) { }
+fn putstr(_s: ~str) { }
-fn putint(i: int) {
+fn putint(_i: int) {
let mut i: int = 33;
while i < 36 { putstr(~"hi"); i = i + 1; }
}
// Exercise some of the configured items in ways that wouldn't be possible
// if they had the bogus definition
assert!((b));
- let x: t = true;
- let y: tg = bar;
+ let _x: t = true;
+ let _y: tg = bar;
test_in_fn_ctxt();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
static x : [int, ..4] = [1,2,3,4];
static p : int = x[2];
static y : &'static [int] = &[1,2,3,4];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
struct Pair<'self> { a: int, b: &'self int }
static x: &'static int = &10;
// except according to those terms.
use std::cmp;
-use std::io;
struct foo { a: int, b: int, c: int }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
static x : [int, ..4] = [1,2,3,4];
static y : &'static [int] = &[1,2,3,4];
// instead of in std.
use std::libc;
-use std::os;
use std::run::*;
use std::run;
use std::str;
// except according to those terms.
pub fn main() {
- let x = ~[
+ let _x = ~[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-pub fn main() { let x: @int = @10; let y: int = *x; }
+pub fn main() {
+ let x: @int = @10;
+ let _y: int = *x;
+}
}
pub fn main() {
- use std::hash::{Hash, HashUtil}; // necessary for IterBytes check
+ use std::hash::HashUtil; // necessary for IterBytes check
let a = Foo {bar: 4, baz: -3};
}
pub fn main() {
- use std::hash::{Hash, HashUtil}; // necessary for IterBytes check
+ use std::hash::HashUtil; // necessary for IterBytes check
let a = Foo {bar: 4, baz: -3};
// Just testing that fail!() type checks in statement or expr
+#[allow(unreachable_code)];
+
fn f() {
fail!();
- let x: int = fail!();
+ let _x: int = fail!();
}
pub fn main() {
// no-reformat
// Testing various forms of `do` with empty arg lists
-fn f(f: &fn() -> bool) -> bool {
+fn f(_f: &fn() -> bool) -> bool {
true
}
// Testing that we can drop the || in do exprs
-fn f(f: @fn() -> bool) -> bool { true }
+fn f(_f: @fn() -> bool) -> bool { true }
-fn d(f: @fn()) { }
+fn d(_f: @fn()) { }
pub fn main() {
do d { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f(f: &fn()) {
+fn f(_f: &fn()) {
}
fn g() {
bar: int
}
-fn g(i: int) { }
+fn g(_i: int) { }
fn f(foo: @@Quux) { g(foo.bar); }
pub fn main() { }
enum t { foo(@int), }
-pub fn main() { let tt = foo(@10); match tt { foo(z) => { } } }
+pub fn main() {
+ let tt = foo(@10);
+ match tt { foo(_z) => { } }
+}
// -*- rust -*-
-fn f() -> int { if true { let s: ~str = ~"should not leak"; return 1; } return 0; }
+fn f() -> int {
+ if true {
+ let _s: ~str = ~"should not leak";
+ return 1;
+ }
+ return 0;
+}
pub fn main() { f(); }
}
pub fn main() {
- let x = S { x: 1 };
+ let _x = S { x: 1 };
}
}
pub fn main() {
- let x: Foo = Foo { x: 3 };
+ let _x: Foo = Foo { x: 3 };
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_mut)];
-
-pub fn main() { let mut v: ~[int] = ~[]; }
+pub fn main() { let mut _v: ~[int] = ~[]; }
fn addr_of<T>(ptr: &T) -> uint {
let ptr = ptr::to_unsafe_ptr(ptr);
- unsafe { ptr as uint }
+ ptr as uint
}
fn is_aligned<T>(ptr: &T) -> bool {
test_color(imaginary, -1, ~"imaginary");
}
-fn test_color(color: color, val: int, name: ~str) {
+fn test_color(color: color, val: int, _name: ~str) {
assert!(color as int == val);
assert!(color as float == val as float);
}
}
pub fn main() {
- let x = a::Bar;
+ let _x = a::Bar;
}
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
enum Animal {
Dog (~str, float),
Cat { name: ~str, weight: float }
let mut a: Animal = Dog(~"Cocoa", 37.2);
a = Cat{ name: ~"Spotty", weight: 2.7 };
// permuting the fields should work too
- let c = Cat { weight: 3.1, name: ~"Spreckles" };
+ let _c = Cat { weight: 3.1, name: ~"Spreckles" };
}
static BAR2:uint = BAR;
fn main() {
- let v = [0, .. Bunny as uint];
- let v = [0, .. BAR];
- let v = [0, .. BAR2];
+ let _v = [0, .. Bunny as uint];
+ let _v = [0, .. BAR];
+ let _v = [0, .. BAR2];
static BAR3:uint = BAR2;
- let v = [0, .. BAR3];
-}
\ No newline at end of file
+ let _v = [0, .. BAR3];
+}
pub fn main() {
let x = &"hello";
let v = &"hello";
- let mut y : &str = &"there";
+ let y : &str = &"there";
info!(x);
info!(y);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let x : ~str = ~"hello";
let _y : ~str = ~"there";
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let x : [@int, ..5] = [@1,@2,@3,@4,@5];
let _y : [@int, ..5] = [@1,@2,@3,@4,@5];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let x : &[int] = &[1,2,3,4,5];
let mut z = &[1,2,3,4,5];
use std::os;
pub fn main() {
- assert_eq!(os::getenv(~"TEST_EXEC_ENV"), Some(~"22"));
+ assert_eq!(os::getenv("TEST_EXEC_ENV"), Some(~"22"));
}
pub fn f() -> t { return t1; }
}
-pub fn main() { let v: foo::t = foo::f(); }
+pub fn main() { let _v: foo::t = foo::f(); }
pub static a : int = 10;
}
pub fn zum() {
- let b = a;
+ let _b = a;
}
}
pub enum t { t1, }
}
-pub fn main() { let v = foo::t1; }
+pub fn main() { let _v = foo::t1; }
type t = @fn() -> int;
fn ten() -> int { return 10; }
let rs: t = { ten };
- //assert!((rs() == 10));
+ assert!((rs() == 10));
}
pub fn main() { test_fn(); }
// except according to those terms.
// Regression test for issue #388
-pub fn main() { let x = { { @10 } }; }
+pub fn main() { let _x = { { @10 } }; }
// values from the else if branch
pub fn main() {
let y: @uint = @10u;
- let x = if false { y } else if true { y } else { y };
+ let _x = if false { y } else if true { y } else { y };
assert_eq!(*y, 10u);
}
// except according to those terms.
// Regression test for issue #388
-pub fn main() { let x = if false { @0u } else if true { @10u } else { @0u }; }
+pub fn main() {
+ let _x = if false {
+ @0u
+ } else if true {
+ @10u
+ } else {
+ @0u
+ };
+}
// Issue #521
-fn f() { let x = match true { true => { 10 } false => { return } }; }
+fn f() {
+ let _x = match true {
+ true => { 10 }
+ false => { return }
+ };
+}
pub fn main() { }
// When all branches of an if expression result in fail, the entire if
// expression results in fail.
-pub fn main() { let x = if true { 10 } else { if true { fail!() } else { fail!() } }; }
+pub fn main() {
+ let _x = if true {
+ 10
+ } else {
+ if true { fail!() } else { fail!() }
+ };
+}
// When all branches of an match expression result in fail, the entire
// match expression results in fail.
pub fn main() {
- let x =
+ let _x =
match true {
true => { 10 }
false => { match true { true => { fail!() } false => { fail!() } } }
}
fn test_inferrence() {
- let mut rs = match true { true => { true } false => { false } };
+ let rs = match true { true => { true } false => { false } };
assert!((rs));
}
}
}
+#[fixed_stack_segment]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
extern mod externcallback(vers = "0.1");
+#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
extern mod extra;
use extra::json::Object;
pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU32s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_TwoU64s(u: TwoU64s) -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u8, rust_dbg_extern_identity_u8(22_u8));
pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64));
pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u32, rust_dbg_extern_identity_u32(22_u32));
pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u64, rust_dbg_extern_identity_u64(22_u64));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 #5745
-// xfail-macos Broken on mac i686
-
struct TwoU16s {
one: u16, two: u16
}
pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU16s();
pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU32s();
pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU64s();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 #5745
-// xfail-macos Broken on mac i686
-
struct TwoU8s {
one: u8, two: u8
}
pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU8s();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// This creates a bunch of yielding tasks that run concurrently
+// This creates a bunch of descheduling tasks that run concurrently
// while holding onto C stacks
use std::libc;
if data == 1u {
data
} else {
- task::yield();
+ task::deschedule();
count(data - 1u) + count(data - 1u)
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
rustrt::rust_dbg_call(cb, n)
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
- task::yield();
+ task::deschedule();
rustrt::rust_dbg_call(cb, n)
}
}
pub fn main() {
fn f() {}
- let i: r = r {field: f};
+ let _i: r = r {field: f};
}
// -*- rust -*-
-fn foo(f: extern fn(int) -> int) { }
+fn foo(_f: extern fn(int) -> int) { }
fn id(x: int) -> int { return x; }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
+
pub fn main() {
// We should be able to type infer inside of @fns.
- let f = || {
+ let _f = || {
let i = 10;
};
}
use std::libc;
use std::unstable::run_in_bare_thread;
-extern {
- pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t;
-}
+externfn!(fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t)
pub fn main() {
unsafe {
do run_in_bare_thread() {
- unsafe {
- let i = &100;
- rust_dbg_call(callback, cast::transmute(i));
- }
+ let i = &100;
+ rust_dbg_call(callback, cast::transmute(i));
}
}
}
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt1::rust_get_test_int();
extern mod extra;
-use std::libc;
-use std::str;
-use std::vec;
-
mod libc {
+ use std::libc::{c_char, size_t};
+
#[nolink]
#[abi = "cdecl"]
extern {
#[link_name = "strlen"]
- pub fn my_strlen(str: *u8) -> uint;
+ pub fn my_strlen(str: *c_char) -> size_t;
}
}
+#[fixed_stack_segment] #[inline(never)]
fn strlen(str: ~str) -> uint {
- unsafe {
- // C string is terminated with a zero
- do str.to_c_str().with_ref |buf| {
- libc::my_strlen(buf as *u8)
+ // C string is terminated with a zero
+ do str.with_c_str |buf| {
+ unsafe {
+ libc::my_strlen(buf) as uint
}
}
}
// except according to those terms.
mod foo {
+ use std::libc::c_int;
+
#[nolink]
extern {
- pub static errno: int;
+ pub static errno: c_int;
}
}
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt::rust_get_test_int();
}
mod libc {
+ use std::libc::{c_int, c_void, size_t, ssize_t};
+
#[abi = "cdecl"]
#[nolink]
extern {
- pub fn write(fd: int, buf: *u8, count: ::std::libc::size_t)
- -> ::std::libc::ssize_t;
+ pub fn write(fd: c_int, buf: *c_void, count: size_t) -> ssize_t;
}
}
struct Pair { x: @int, y: @int }
-fn f<T>(t: T) { let t1: T = t; }
+fn f<T>(t: T) { let _t1: T = t; }
pub fn main() { let x = Pair {x: @10, y: @12}; f(x); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(dead_assignment)];
// -*- rust -*-
fn id<T>(x: T) -> T { return x; }
enum wrapper<T> { wrapped(T), }
-pub fn main() { let w = wrapped(~[1, 2, 3, 4, 5]); }
+pub fn main() { let _w = wrapped(~[1, 2, 3, 4, 5]); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f<T>(v: @T) { }
+fn f<T>(_v: @T) { }
pub fn main() { f(@~[1, 2, 3, 4, 5]); }
enum list<T> { cons(@T, @list<T>), nil, }
pub fn main() {
- let a: list<int> =
+ let _a: list<int> =
cons::<int>(@10, @cons::<int>(@12, @cons::<int>(@13, @nil::<int>)));
}
// This causes memory corruption in stage0.
enum thing<K> { some(K), }
-pub fn main() { let x = some(~"hi"); }
+pub fn main() { let _x = some(~"hi"); }
enum clam<T> { a(T), }
-pub fn main() { let c = a(3); }
+pub fn main() { let _c = a(3); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
enum foo<T> { arm(T), }
fn altfoo<T>(f: foo<T>) {
let mut hit = false;
- match f { arm::<T>(x) => { info!("in arm"); hit = true; } }
+ match f { arm::<T>(_x) => { info!("in arm"); hit = true; } }
assert!((hit));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
enum option<T> { some(@T), none, }
-pub fn main() { let mut a: option<int> = some::<int>(@10); a = none::<int>; }
+pub fn main() {
+ let mut a: option<int> = some::<int>(@10);
+ a = none::<int>;
+}
type Bar<T> = Foo<T>;
-fn takebar<T>(b: Bar<T>) { }
+fn takebar<T>(_b: Bar<T>) { }
pub fn main() { }
pub fn main() {
let args = ~[];
- let opts = ~[optopt(~"b")];
+ let opts = ~[optopt("b")];
match getopts(args, opts) {
Ok(ref m) =>
match Pair {x: 10, y: 20} {
x if x.x < 5 && x.y < 5 => { 1 }
Pair {x: x, y: y} if x == 10 && y == 20 => { 2 }
- Pair {x: x, y: y} => { 3 }
+ Pair {x: _x, y: _y} => { 3 }
};
assert_eq!(b, 2);
}
)
pub fn main() {
- let page = html! (
+ let _page = html! (
<html>
<head><title>This is the title.</title></head>
<body>
macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) })
// Make sure there's a poly formatter that takes anything
- t!(ifmt!("{}", 1), "1");
- t!(ifmt!("{}", A), "{}");
- t!(ifmt!("{}", ()), "()");
- t!(ifmt!("{}", @(~1, "foo")), "@(~1, \"foo\")");
+ t!(ifmt!("{:?}", 1), "1");
+ t!(ifmt!("{:?}", A), "{}");
+ t!(ifmt!("{:?}", ()), "()");
+ t!(ifmt!("{:?}", @(~1, "foo")), "@(~1, \"foo\")");
// Various edge cases without formats
t!(ifmt!(""), "");
t!(ifmt!("hello"), "hello");
t!(ifmt!("hello \\{"), "hello {");
+ // default formatters should work
+ t!(ifmt!("{}", 1i), "1");
+ t!(ifmt!("{}", 1i8), "1");
+ t!(ifmt!("{}", 1i16), "1");
+ t!(ifmt!("{}", 1i32), "1");
+ t!(ifmt!("{}", 1i64), "1");
+ t!(ifmt!("{}", 1u), "1");
+ t!(ifmt!("{}", 1u8), "1");
+ t!(ifmt!("{}", 1u16), "1");
+ t!(ifmt!("{}", 1u32), "1");
+ t!(ifmt!("{}", 1u64), "1");
+ t!(ifmt!("{}", 1.0f), "1");
+ t!(ifmt!("{}", 1.0f32), "1");
+ t!(ifmt!("{}", 1.0f64), "1");
+ t!(ifmt!("{}", "a"), "a");
+ t!(ifmt!("{}", ~"a"), "a");
+ t!(ifmt!("{}", @"a"), "a");
+ t!(ifmt!("{}", false), "false");
+ t!(ifmt!("{}", 'a'), "a");
+
// At least exercise all the formats
t!(ifmt!("{:b}", true), "true");
t!(ifmt!("{:c}", '☃'), "☃");
t!(ifmt!("{:x}", 10u), "a");
t!(ifmt!("{:X}", 10u), "A");
t!(ifmt!("{:s}", "foo"), "foo");
+ t!(ifmt!("{:s}", ~"foo"), "foo");
+ t!(ifmt!("{:s}", @"foo"), "foo");
t!(ifmt!("{:p}", 0x1234 as *int), "0x1234");
t!(ifmt!("{:p}", 0x1234 as *mut int), "0x1234");
t!(ifmt!("{:d}", A), "aloha");
t!(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1");
t!(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
t!(ifmt!("{} {0:s}", "a"), "a a");
- t!(ifmt!("{} {0}", "a"), "\"a\" \"a\"");
+ t!(ifmt!("{} {0}", "a"), "a a");
// Methods should probably work
t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
extern mod extra;
use std::vec::*;
pub fn main() {
let mut v = from_elem(0u, 0);
- v = append(v, ~[4, 2]);
+ v = append(v, [4, 2]);
assert_eq!(from_fn(2, |i| 2*(i+1)), ~[2, 4]);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
use baz::zed;
use baz::zed::bar;
pub fn bar() { info!("bar"); }
}
-pub fn main() { let zed = 42; bar(); }
+pub fn main() { let _zed = 42; bar(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
use foo::zed;
use bar::baz;
+
mod foo {
pub mod zed {
pub fn baz() { info!("baz"); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
use foo::zed;
use bar::baz;
+
mod foo {
pub mod zed {
pub fn baz() { info!("baz"); }
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.i) = *(self.i) + 1;
- }
+ *(self.i) = *(self.i) + 1;
}
}
fn test_box() {
let i = @mut 0;
{
- let a = @r(i);
+ let _a = @r(i);
}
assert_eq!(*i, 1);
}
fn test_rec() {
let i = @mut 0;
{
- let a = Box {x: r(i)};
+ let _a = Box {x: r(i)};
}
assert_eq!(*i, 1);
}
let i = @mut 0;
{
- let a = t0(r(i));
+ let _a = t0(r(i));
}
assert_eq!(*i, 1);
}
fn test_tup() {
let i = @mut 0;
{
- let a = (r(i), 0);
+ let _a = (r(i), 0);
}
assert_eq!(*i, 1);
}
fn test_unique() {
let i = @mut 0;
{
- let a = ~r(i);
+ let _a = ~r(i);
}
assert_eq!(*i, 1);
}
fn test_box_rec() {
let i = @mut 0;
{
- let a = @Box {
+ let _a = @Box {
x: r(i)
};
}
struct X { x: uint, nxt: *foo }
pub fn main() {
- let x = foo(X {x: 0, nxt: ptr::null()});
+ let _x = foo(X {x: 0, nxt: ptr::null()});
}
// -*- rust -*-
-pub fn main() { let x: int = 10; }
+pub fn main() { let _x: int = 10; }
use cci_intrinsic::atomic_xchg;
pub fn main() {
- unsafe {
- let mut x = 1;
- atomic_xchg(&mut x, 5);
- assert_eq!(x, 5);
- }
+ let mut x = 1;
+ atomic_xchg(&mut x, 5);
+ assert_eq!(x, 5);
}
pub fn main() {
unsafe {
- let mut x = @1;
+ let x = @1;
let mut y = @2;
rusti::move_val(&mut y, x);
assert_eq!(*y, 1);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::f64;
-
mod rusti {
#[abi = "rust-intrinsic"]
extern "rust-intrinsic" {
extern mod foreign_lib;
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
- let foo = foreign_lib::rustrt::rust_get_test_int();
+ let _foo = foreign_lib::rustrt::rust_get_test_int();
}
}
// except according to those terms.
use std::hashmap::HashMap;
-use std::str;
pub fn main() {
let mut m = HashMap::new();
use std::cast;
use std::libc::{c_double, c_int};
-use std::f64::*;
fn to_c_int(v: &mut int) -> &mut c_int {
unsafe {
}
}
+#[fixed_stack_segment] #[inline(never)]
fn lgamma(n: c_double, value: &mut int) -> c_double {
unsafe {
return m::lgamma(n, to_c_int(value));
}
impl<A> clam<A> for foo<A> {
- fn chowder(&self, y: A) {
+ fn chowder(&self, _y: A) {
}
}
}
impl<A> foo<A> {
- pub fn bar<B,C:clam<A>>(&self, c: C) -> B {
+ pub fn bar<B,C:clam<A>>(&self, _c: C) -> B {
fail!();
}
}
struct foo(int);
impl foo {
- pub fn bar<B,C:clam<B>>(&self, c: C) -> B { fail!(); }
+ pub fn bar<B,C:clam<B>>(&self, _c: C) -> B { fail!(); }
}
pub fn main() { }
// except according to those terms.
pub fn main() {
- let foo = 100;
+ let _foo = 100;
static quux: int = 5;
enum Stuff {
}
impl<T> c1<T> {
- pub fn f1(&self, x: int) {
+ pub fn f1(&self, _x: int) {
}
}
}
impl<T> c1<T> {
- pub fn f2(&self, x: int) {
+ pub fn f2(&self, _x: int) {
}
}
}
impl<T> c1<T> {
- pub fn f1(&self, x: T) {}
+ pub fn f1(&self, _x: T) {}
}
fn c1<T>(x: T) -> c1<T> {
}
impl<T> c1<T> {
- pub fn f2(&self, x: T) {}
+ pub fn f2(&self, _x: T) {}
}
g: 0,
};
- let y = Pair {
+ let _y = Pair {
f: 1,
g: 1,
.. x
};
- let z = Pair {
+ let _z = Pair {
f: 1,
.. x
};
// xfail-fast
// aux-build:issue-2526.rs
+#[allow(unused_imports)];
+
extern mod issue_2526;
use issue_2526::*;
}
pub fn main() {
- let mut kitty = cat();
+ let kitty = cat();
nyan(kitty, KittyInfo {kitty: kitty});
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::util;
-
pub type Task = int;
// tjc: I don't know why
// We should consider moving this to ::std::unsafe, although I
// suspect graydon would want us to use void pointers instead.
pub unsafe fn uniquify<T>(x: *T) -> ~T {
- unsafe { cast::transmute(x) }
+ cast::transmute(x)
}
pub fn swap_state_acq(dst: &mut state, src: state) -> state {
}
pub fn send<T:Send>(mut p: send_packet<T>, payload: T) {
- let mut p = p.unwrap();
+ let p = p.unwrap();
let mut p = unsafe { uniquify(p) };
assert!((*p).payload.is_none());
(*p).payload = Some(payload);
}
pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> {
- let mut p = p.unwrap();
+ let p = p.unwrap();
let mut p = unsafe { uniquify(p) };
loop {
let old_state = swap_state_acq(&mut (*p).state,
blocked);
match old_state {
- empty | blocked => { task::yield(); }
+ empty | blocked => { task::deschedule(); }
full => {
let payload = util::replace(&mut p.payload, None);
return Some(payload.unwrap())
}
}
- pub fn sender_terminate<T:Send>(mut p: *packet<T>) {
+ pub fn sender_terminate<T:Send>(p: *packet<T>) {
let mut p = unsafe { uniquify(p) };
match swap_state_rel(&mut (*p).state, terminated) {
empty | blocked => {
}
}
- pub fn receiver_terminate<T:Send>(mut p: *packet<T>) {
+ pub fn receiver_terminate<T:Send>(p: *packet<T>) {
let mut p = unsafe { uniquify(p) };
match swap_state_rel(&mut (*p).state, terminated) {
empty => {
pub mod pingpong {
use std::cast;
- use std::ptr;
- use std::util;
pub struct ping(::pipes::send_packet<pong>);
pub struct pong(::pipes::send_packet<ping>);
pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> {
unsafe {
- let addr : *::pipes::send_packet<pong> = match &p {
+ let _addr : *::pipes::send_packet<pong> = match &p {
&ping(ref x) => { cast::transmute(x) }
};
fail!()
pub fn liberate_pong(p: pong) -> ::pipes::send_packet<ping> {
unsafe {
- let addr : *::pipes::send_packet<ping> = match &p {
+ let _addr : *::pipes::send_packet<ping> = match &p {
&pong(ref x) => { cast::transmute(x) }
};
fail!()
}
pub mod client {
- use std::option;
use pingpong;
pub type ping = ::pipes::send_packet<pingpong::ping>;
}
}
-fn add_interface(store: int, managed_ip: ~str, data: extra::json::Json) -> (~str, object)
+fn add_interface(_store: int, managed_ip: ~str, data: extra::json::Json) -> (~str, object)
{
match &data {
&extra::json::Object(ref interface) => {
use std::io::ReaderUtil;
use std::io;
-use std::str;
use std::to_str;
enum square {
extern mod extra;
-use std::io;
use std::vec;
trait methods {
pub fn main() {
let fd: libc::c_int = 1 as libc::c_int;
- let sock = @socket::socket_handle(fd);
+ let _sock = @socket::socket_handle(fd);
}
pub fn main() {
let x = 1;
let y: @fn() -> int = || x;
- let z = y();
+ let _z = y();
}
// Extern mod controls linkage. Use controls the visibility of names to modules that are
// already linked in. Using WriterUtil allows us to use the write_line method.
-use std::int;
use std::io::WriterUtil;
use std::io;
use std::str;
fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt {
// Use an anonymous function to build a vector of vectors containing
// blank characters for each position in our canvas.
- let mut lines = do vec::build_sized(height) |push| {
+ let lines = do vec::build_sized(height) |push| {
do height.times {
push(vec::from_elem(width, '.'));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+
// rustc --test match_borrowed_str.rs.rs && ./match_borrowed_str.rs
extern mod extra;
pub fn main()
{
assert!(compare("foo", "foo"));
+ assert!(compare(~"foo", ~"foo"));
assert!(compare(@"foo", @"foo"));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
struct Vec2 {
x: float,
y: float
}
pub fn main() {
- let mut x = @mut Foo { x: 3 };
+ let x = @mut Foo { x: 3 };
// Neither of the next two lines should cause an error
let _ = x.stuff();
x.stuff();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main()
-{
+#[allow(path_statement)];
+
+pub fn main() {
let y = ~1;
y;
}
// except according to those terms.
pub fn main() {
- let id: &Mat2<float> = &Matrix::identity();
+ let _id: &Mat2<float> = &Matrix::identity();
}
pub trait Index<Index,Result> { }
// except according to those terms.
pub fn main() {
- let foo = [0, ..2*4];
+ let _foo = [0, ..2*4];
}
--- /dev/null
+// 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.
+
+fn broken<'r>(v: &'r [u8], i: uint, j: uint) -> &'r [u8] { v.slice(i, j) }
+
+pub fn main() {}
let x = os::args();
for arg in x.iter() {
match arg.clone() {
- s => { }
+ _s => { }
}
}
}
impl Drop for NonCopyable {
fn drop(&self) {
let p = **self;
- let v = unsafe { transmute::<*c_void, ~int>(p) };
+ let _v = unsafe { transmute::<*c_void, ~int>(p) };
}
}
fn main() {
let t = ~0;
let p = unsafe { transmute::<~int, *c_void>(t) };
- let z = NonCopyable(p);
+ let _z = NonCopyable(p);
}
--- /dev/null
+// 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.
+
+trait U { fn f(self); }
+impl U for int { fn f(self) {} }
+pub fn main() { 4.f(); }
--- /dev/null
+// 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.
+
+struct T { a: ~int }
+
+trait U {
+ fn f(self);
+}
+
+impl U for ~int {
+ fn f(self) { }
+}
+
+pub fn main() {
+ let T { a: a } = T { a: ~0 };
+ a.f();
+}
+
}
fn main() {
- let mut sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop);
+ let _sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
fn main() {
let s: ~str = ~"foobar";
let mut t: &str = s;
-fn foo<T: ::std::cmp::Eq>(t: T) { }
+fn foo<T: ::std::cmp::Eq>(_t: T) { }
fn main() { }
--- /dev/null
+// 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.
+
+struct Dog {
+ name : ~str
+}
+
+trait Barks {
+ fn bark(&self) -> ~str;
+}
+
+impl Barks for Dog {
+ fn bark(&self) -> ~str {
+ return fmt!("woof! (I'm %s)", self.name);
+ }
+}
+
+
+pub fn main() {
+ let snoopy = ~Dog{name: ~"snoopy"};
+ let bubbles = ~Dog{name: ~"bubbles"};
+ let barker = [snoopy as ~Barks, bubbles as ~Barks];
+
+ for pup in barker.iter() {
+ println(fmt!("%s", pup.bark()));
+ }
+}
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+
use std::io;
fn main() {
--- /dev/null
+// 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.
+
+pub struct Foo {
+ a: int,
+}
+
+struct Bar<'self> {
+ a: ~Option<int>,
+ b: &'self Foo,
+}
+
+fn check(a: @Foo) {
+ let _ic = Bar{ b: a, a: ~None };
+}
+
+pub fn main(){}
--- /dev/null
+// 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.
+
+// xfail-test
+
+use std::io;
+
+struct T (&'static [int]);
+static t : T = T (&'static [5, 4, 3]);
+fn main () {
+ assert_eq!(t[0], 5);
+}
\ No newline at end of file
--- /dev/null
+// 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.
+
+#[allow(unused_mut)];
+
+pub fn main() {
+ let mut your_favorite_numbers = @[1,2,3];
+ let mut my_favorite_numbers = @[4,5,6];
+ let f = your_favorite_numbers + my_favorite_numbers;
+ println(fmt!("The third favorite number is %?.", f))
+}
+
--- /dev/null
+// 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.
+
+pub enum Thing {
+ A(~Foo)
+}
+
+pub trait Foo {}
+
+pub struct Struct;
+
+impl Foo for Struct {}
+
+pub fn main() {
+ match A(~Struct as ~Foo) {
+ A(_a) => 0,
+ };
+}
+
--- /dev/null
+// 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.
+
+// xfail-test
+
+pub mod Bar {
+ pub struct Foo {
+ v: int,
+ }
+
+ extern {
+ #[rust_stack]
+ pub fn foo(v: *Foo) -> Foo;
+ }
+}
+
+fn main() { }
+
--- /dev/null
+// 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.
+
+fn foo(~(_x, _y): ~(int, int)) {}
+
+pub fn main() {}
--- /dev/null
+// 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.
+
+use std::unstable::intrinsics;
+
+/// Returns the size of a type
+pub fn size_of<T>() -> uint {
+ TypeInfo::size_of::<T>()
+}
+
+/// Returns the size of the type that `val` points to
+pub fn size_of_val<T>(val: &T) -> uint {
+ val.size_of_val()
+}
+
+pub trait TypeInfo {
+ fn size_of() -> uint;
+ fn size_of_val(&self) -> uint;
+}
+
+impl<T> TypeInfo for T {
+ /// The size of the type in bytes.
+ fn size_of() -> uint {
+ unsafe { intrinsics::size_of::<T>() }
+ }
+
+ /// Returns the size of the type of `self` in bytes.
+ fn size_of_val(&self) -> uint {
+ TypeInfo::size_of::<T>()
+ }
+}
+
+pub fn main() {}
--- /dev/null
+// 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.
+
+// aux-build:iss.rs
+// xfail-fast
+
+extern mod iss ( name = "iss6919_3" );
+
+pub fn main() {
+ iss::D.k;
+}
+
--- /dev/null
+// 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.
+
+pub fn main() {
+ static FOO: float = 10.0;
+
+ match 0.0 {
+ 0.0 .. FOO => (),
+ _ => ()
+ }
+}
+
--- /dev/null
+// 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.
+
+trait A {}
+struct B;
+impl A for B {}
+
+fn foo(_: &mut A) {}
+
+fn main() {
+ let mut b = B;
+ foo(&mut b as &mut A);
+}
+
--- /dev/null
+// 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.
+
+trait A {}
+struct B;
+impl A for B {}
+
+struct C<'self> {
+ foo: &'self mut A,
+}
+
+fn foo(a: &mut A) {
+ C{ foo: a };
+}
+
+fn main() {
+}
+
--- /dev/null
+// 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.
+
+use std::rt::io;
+
+fn foo(a: &mut io::Writer) {
+ a.write([])
+}
+
+fn main(){}
+
--- /dev/null
+// 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.
+
+// aux-build:issue_8401.rs
+// xfail-fast
+
+extern mod issue_8401;
+
+pub fn main() {}
--- /dev/null
+// 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.
+
+// xfail-test
+use std::io;
+
+fn main() {
+// This is ok
+ match &[(~5,~7)] {
+ ps => {
+ let (ref y, _) = ps[0];
+ io::println(fmt!("1. y = %d", **y));
+ assert!(**y == 5);
+ }
+ }
+
+// This is not entirely ok
+ match Some(&[(~5,)]) {
+ Some(ps) => {
+ let (ref y,) = ps[0];
+ io::println(fmt!("2. y = %d", **y));
+ if **y != 5 { io::println("sadness"); }
+ }
+ None => ()
+ }
+
+// This is not ok
+ match Some(&[(~5,~7)]) {
+ Some(ps) => {
+ let (ref y, ref z) = ps[0];
+ io::println(fmt!("3. y = %d z = %d", **y, **z));
+ assert!(**y == 5);
+ }
+ None => ()
+ }
+}
+
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.b) += 1;
- }
+ *(self.b) += 1;
}
}
pub fn main() {
let b = @mut 0;
{
- let p = Some(r(b));
+ let _p = Some(r(b));
}
assert_eq!(*b, 1);
fn test_heap_log() { let s = ~"a big ol' string"; info!(s); }
fn test_stack_add() {
- assert_eq!(~"a" + ~"b", ~"ab");
+ assert_eq!(~"a" + "b", ~"ab");
let s: ~str = ~"a";
assert_eq!(s + s, ~"aa");
- assert_eq!(~"" + ~"", ~"");
+ assert_eq!(~"" + "", ~"");
}
-fn test_stack_heap_add() { assert!((~"a" + ~"bracadabra" == ~"abracadabra")); }
+fn test_stack_heap_add() { assert!((~"a" + "bracadabra" == ~"abracadabra")); }
fn test_heap_add() {
- assert_eq!(~"this should" + ~" totally work", ~"this should totally work");
+ assert_eq!(~"this should" + " totally work", ~"this should totally work");
}
fn test_append() {
let mut s = ~"";
- s.push_str(~"a");
+ s.push_str("a");
assert_eq!(s, ~"a");
let mut s = ~"a";
- s.push_str(~"b");
+ s.push_str("b");
info!(s.clone());
assert_eq!(s, ~"ab");
let mut s = ~"c";
- s.push_str(~"offee");
+ s.push_str("offee");
assert!(s == ~"coffee");
- s.push_str(~"&tea");
+ s.push_str("&tea");
assert!(s == ~"coffee&tea");
}
extern mod extra;
pub fn f() {
- fmt!("test%s", ~"s");
+ fmt!("test%s", "s");
#[attr = "val"]
fn g() { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f(a: ~[int]) { }
+fn f(_a: ~[int]) { }
pub fn main() { f(~[1, 2, 3, 4, 5]); }
-use std::comm::*;
use std::task;
fn producer(c: &Chan<~[u8]>) {
pub fn main() {
let (p, ch) = stream::<~[u8]>();
- let prod = task::spawn(|| producer(&ch) );
+ let _prod = task::spawn(|| producer(&ch) );
- let data: ~[u8] = p.recv();
+ let _data: ~[u8] = p.recv();
}
pub fn main() {
let e = @mut Refs{refs: ~[], n: 0};
- let f: @fn() = || error!(e.n);
+ let _f: @fn() = || error!(e.n);
e.refs.push(1);
}
k: int,
l: int}
fn f() {
- let foo: Large =
+ let _foo: Large =
Large {a: 0,
b: 0,
c: 0,
-fn leaky<T>(t: T) { }
+fn leaky<T>(_t: T) { }
pub fn main() { let x = @10; leaky::<@int>(x); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
enum t { a, b(@int), }
-fn leaky<T>(t: T) { }
+fn leaky<T>(_t: T) { }
pub fn main() { let x = ~10; leaky::<~int>(x); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
struct X { x: int, y: @A }
struct A { a: int }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn test(cond: bool) {
+#[allow(dead_assignment)];
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
+fn test(_cond: bool) {
let v: int;
v = 1;
loop { } // loop never terminates, so no error is reported
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+
fn test() {
let _v: int;
_v = 1;
-pub fn main() { if false { error!(~"foo" + ~"bar"); } }
+pub fn main() { if false { error!(~"foo" + "bar"); } }
}
pub fn main() {
- let x = list::from_vec(~[a(22u), b(~"hi")]);
+ let x = list::from_vec([a(22u), b(~"hi")]);
let exp = ~"@Cons(a(22), @Cons(b(~\"hi\"), @Nil))";
let act = fmt!("%?", x);
assert!(act == exp);
struct V<T> { v: ~[option<T>] }
fn mk<T:'static>() -> @mut Smallintmap<T> {
- let mut v: ~[option<T>] = ~[];
+ let v: ~[option<T>] = ~[];
return @mut Smallintmap {v: v};
}
fn f<T,U:'static>() {
- let mut sim = mk::<U>();
+ let sim = mk::<U>();
error!(sim);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
-
-pub fn main() { let mut i: int = 0; while i < 1000000 { i += 1; let x = 3; } }
+pub fn main() {
+ let mut i: int = 0;
+ while i < 1000000 {
+ i += 1;
+ let x = 3;
+ }
+}
// except according to those terms.
pub fn main() {
- let i = 0u;
+ let _i = 0u;
loop {
break;
}
--- /dev/null
+// 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.
+
+use std::local_data;
+
+local_data_key!(foo: int)
+
+mod bar {
+ local_data_key!(pub baz: float)
+}
+
+fn main() {
+ local_data::get(foo, |x| assert!(x.is_none()));
+ local_data::get(bar::baz, |y| assert!(y.is_none()));
+
+ local_data::set(foo, 3);
+ local_data::set(bar::baz, -10.0);
+
+ local_data::get(foo, |x| assert_eq!(*x.unwrap(), 3));
+ local_data::get(bar::baz, |y| assert_eq!(*y.unwrap(), -10.0));
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+
fn f1(ref_string: &str) -> ~str {
match ref_string {
"a" => ~"found a",
pub fn main() {
let mut x = ~Pair {a: ~10, b: ~20};
match x {
- ~Pair {a: ref mut a, b: ref mut b} => {
+ ~Pair {a: ref mut a, b: ref mut _b} => {
assert!(**a == 10); *a = ~30; assert!(**a == 30);
}
}
struct X { x: int }
pub fn main() {
- let x = match 0 {
+ let _x = match 0 {
_ => X {
x: 0
}.x
struct X { x: int }
pub fn main() {
- let x = match 0 {
+ let _x = match 0 {
_ => X {
x: 0
}
enum maybe<T> { nothing, just(T), }
fn foo(x: maybe<int>) {
- match x { nothing => { error!("A"); } just(a) => { error!("B"); } }
+ match x {
+ nothing => { error!("A"); }
+ just(_a) => { error!("B"); }
+ }
}
pub fn main() { }
-fn altsimple(f: int) { match f { x => () } }
+fn altsimple(f: int) { match f { _x => () } }
pub fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
enum thing { a, b, c, }
--- /dev/null
+// 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.
+
+fn test1() {
+ // from issue 6338
+ match ((1, ~"a"), (2, ~"b")) {
+ ((1, a), (2, b)) | ((2, b), (1, a)) => {
+ assert_eq!(a, ~"a");
+ assert_eq!(b, ~"b");
+ },
+ _ => fail!(),
+ }
+}
+
+fn test2() {
+ match (1, 2, 3) {
+ (1, a, b) | (2, b, a) => {
+ assert_eq!(a, 2);
+ assert_eq!(b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn test3() {
+ match (1, 2, 3) {
+ (1, ref a, ref b) | (2, ref b, ref a) => {
+ assert_eq!(*a, 2);
+ assert_eq!(*b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn test4() {
+ match (1, 2, 3) {
+ (1, a, b) | (2, b, a) if a == 2 => {
+ assert_eq!(a, 2);
+ assert_eq!(b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn test5() {
+ match (1, 2, 3) {
+ (1, ref a, ref b) | (2, ref b, ref a) if *a == 2 => {
+ assert_eq!(*a, 2);
+ assert_eq!(*b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn main() {
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+}
// sometimes we have had trouble finding
// the right type for f, as we unified
// bot and u32 here
- let f = match uint::from_str(~"1234") {
+ let f = match uint::from_str("1234") {
None => return (),
Some(num) => num as u32
};
pub fn f() -> ~[int] { vec::from_elem(1u, 0) }
}
-pub fn main() { let x = m::f(); }
+pub fn main() { let _x = m::f(); }
pub fn main() {
let x = m::S { x: 1, y: 2 };
- let m::S { x: a, y: b } = x;
+ let m::S { x: _a, y: _b } = x;
}
assert_eq!(transform(Some(10)), Some(~"11"));
assert_eq!(transform(None), None);
assert!((~[~"hi"])
- .bind(|x| ~[x.clone(), *x + ~"!"] )
- .bind(|x| ~[x.clone(), *x + ~"?"] ) ==
+ .bind(|x| ~[x.clone(), *x + "!"] )
+ .bind(|x| ~[x.clone(), *x + "?"] ) ==
~[~"hi", ~"hi?", ~"hi!", ~"hi!?"]);
}
pub fn main() {
let x = @Triple{x: 1, y: 2, z: 3};
- for i in range(0u, 10000u) {
+ for _i in range(0u, 10000u) {
assert_eq!(test(true, x), 2);
}
assert_eq!(test(false, x), 5);
// except according to those terms.
// Issue #922
-fn f2(thing: @fn()) { }
+fn f2(_thing: @fn()) { }
fn f(thing: @fn()) {
f2(thing);
-use std::str;
-
struct StringBuffer {
s: ~str
}
sb.append("World!");
let str = to_str(sb);
assert_eq!(str, ~"Hello, World!");
-}
\ No newline at end of file
+}
// except according to those terms.
pub fn main() {
- let x: &mut [int] = &mut [ 1, 2, 3 ];
+ let _x: &mut [int] = &mut [ 1, 2, 3 ];
}
// -*- rust -*-
extern mod extra;
-use std::vec;
-
fn grow(v: &mut ~[int]) {
v.push(1);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_mut)];
struct Pair { a: int, b: int}
pub fn main() {
// This just tests whether the vec leaks its members.
- let mut pvec: ~[@Pair] =
+ let mut _pvec: ~[@Pair] =
~[@Pair{a: 1, b: 2}, @Pair{a: 3, b: 4}, @Pair{a: 5, b: 6}];
}
fn foo() {
match Some::<int>(5) {
- Some::<int>(x) => {
+ Some::<int>(_x) => {
let mut bar;
match None::<int> { None::<int> => { bar = 5; } _ => { baz(); } }
info!(bar);
fn nested(o: t) {
match o {
- bar(i, Some::<int>(_)) => { error!("wrong pattern matched"); fail!(); }
- _ => { error!("succeeded"); }
+ bar(_i, Some::<int>(_)) => { error!("wrong pattern matched"); fail!(); }
+ _ => { error!("succeeded"); }
}
}
pub fn main() {
match A {a: 10, b: @20} {
x@A {a, b: @20} => { assert!(x.a == 10); assert!(a == 10); }
- A {b, _} => { fail!(); }
+ A {b: _b, _} => { fail!(); }
}
let mut x@B {b, _} = B {a: 10, b: C {c: 20}};
x.b.c = 30;
// except according to those terms.
pub fn main() {
- let x: @mut [int] = @mut [ 1, 2, 3 ];
+ let _x: @mut [int] = @mut [ 1, 2, 3 ];
}
fn f(i: int, f: &fn(int) -> int) -> int { f(i) }
-fn g(g: &fn()) { }
+fn g(_g: &fn()) { }
fn ff() -> @fn(int) -> int {
return |x| x + 1;
fn main() {
let y = @mut 32;
{
- let x = Foo(y);
+ let _x = Foo(y);
}
assert_eq!(*y, 23);
}
pub struct Fd(c_int);
impl Drop for Fd {
+ #[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
libc::close(**self);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
pub fn main() {
let thing = ~"{{ f }}";
- let f = thing.find_str(~"{{");
+ let f = thing.find_str("{{");
if f.is_none() {
- println(~"None!");
+ println("None!");
}
}
impl Drop for dtor {
fn drop(&self) {
// abuse access to shared mutable state to write this code
- unsafe {
- *self.x -= 1;
- }
+ *self.x -= 1;
}
}
{
let b = Some(dtor { x:x });
- let c = unwrap(b);
+ let _c = unwrap(b);
}
assert_eq!(*x, 0);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
struct A { a: int, b: int }
struct Abox { a: @int, b: @int }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(unreachable_code)];
// -*- rust -*-
fn dont_call_me() { fail!(); info!(1); }
mod foo {
- pub fn bar(offset: uint) { }
+ pub fn bar(_offset: uint) { }
}
pub fn main() { foo::bar(0u); }
match Some(src) {
Some(src_id) => {
- for i in range(0u, 10u) {
+ for _i in range(0u, 10u) {
let yyy = src_id;
assert_eq!(yyy, 0u);
}
pub fn main() {
let f = |(x, _): (int, int)| println((x + 1).to_str());
- let g = |Foo { x: x, y: y }: Foo| println((x + 1).to_str());
+ let g = |Foo { x: x, y: _y }: Foo| println((x + 1).to_str());
f((2, 3));
g(Foo { x: 1, y: 2 });
}
// this checks that a pred with a non-bool return
// type is rejected, even if the pred is never used
-fn bad(a: int) -> int { return 37; } //~ ERROR Non-boolean return type
+fn bad(_a: int) -> int { return 37; } //~ ERROR Non-boolean return type
pub fn main() { }
}
}
+#[fixed_stack_segment] #[inline(never)]
fn main() {
unsafe {
a::free(transmute(0));
use pub_use_xcrate2::Foo;
pub fn main() {
- let foo: Foo = Foo {
+ let _foo: Foo = Foo {
name: 0
};
}
// xfail-fast
// aux-build:pub_use_mods_xcrate.rs
+#[allow(unused_imports)];
+
extern mod pub_use_mods_xcrate;
use pub_use_mods_xcrate::a::c;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
trait sum {
fn sum_(self) -> int;
}
info!("y==%d", y);
assert_eq!(y, 6);
- let mut x = ~[1, 2, 3];
+ let x = ~[1, 2, 3];
let y = x.sum_();
info!("y==%d", y);
assert_eq!(y, 6);
&foo.v3[i]
}
-fn get_v4<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v4<'v>(a: &'v A, _i: uint) -> &'v int {
let foo = &a.value;
&foo.v4.f
}
-fn get_v5<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v5<'v>(a: &'v A, _i: uint) -> &'v int {
let foo = &a.value;
&foo.v5.f
}
-fn get_v6_a<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v6_a<'v>(a: &'v A, _i: uint) -> &'v int {
match a.value.v6 {
Some(ref v) => &v.f,
None => fail!()
}
}
-fn get_v6_b<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v6_b<'v>(a: &'v A, _i: uint) -> &'v int {
match *a {
A { value: B { v6: Some(ref v), _ } } => &v.f,
_ => fail!()
}
}
-fn get_v6_c<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v6_c<'v>(a: &'v A, _i: uint) -> &'v int {
match a {
&A { value: B { v6: Some(ref v), _ } } => &v.f,
_ => fail!()
}
}
-fn get_v5_ref<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v5_ref<'v>(a: &'v A, _i: uint) -> &'v int {
match &a.value {
&B {v5: ~C {f: ref v}, _} => v
}
x = @5;
y = @6;
assert_eq!(*a, exp);
+ assert_eq!(x, @5);
+ assert_eq!(y, @6);
}
pub fn main() {
fn produce_static<T>() -> &'static T { fail!(); }
-fn foo<T>(x: &T) -> &uint { produce_static() }
+fn foo<T>(_x: &T) -> &uint { produce_static() }
pub fn main() {
}
add(&'self ast<'self>, &'self ast<'self>)
}
-fn mk_add_ok<'a>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast<'a> {
+fn mk_add_ok<'a>(x: &'a ast<'a>, y: &'a ast<'a>, _z: &ast) -> ast<'a> {
add(x, y)
}
// Issue #2263.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
// Should pass region checking.
fn ok(f: @fn(x: &uint)) {
// Here, g is a function that can accept a uint pointer with
x: int
}
+#[fixed_stack_segment] #[inline(never)]
fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
unsafe {
cast::transmute(libc::malloc(sys::size_of::<Bcx<'blk>>()
return alloc(bcx.fcx.arena);
}
+#[fixed_stack_segment] #[inline(never)]
fn g(fcx : &Fcx) {
let bcx = Bcx { fcx: fcx };
let bcx2 = h(&bcx);
--- /dev/null
+// 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.
+
+static FOO: [int, ..4] = [32, ..4];
+static BAR: [int, ..4] = [32, 32, 32, 32];
+
+pub fn main() {
+ assert_eq!(FOO, BAR);
+}
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.i) += 1;
- }
+ *(self.i) += 1;
}
}
impl Drop for r {
fn drop(&self) {
unsafe {
- let v2: ~int = cast::transmute(self.v.c);
+ let _v2: ~int = cast::transmute(self.v.c);
}
}
}
#[unsafe_destructor]
impl Drop for shrinky_pointer {
fn drop(&self) {
- unsafe {
- error!(~"Hello!"); **(self.i) -= 1;
- }
+ error!(~"Hello!"); **(self.i) -= 1;
}
}
#[unsafe_destructor]
impl Drop for close_res {
fn drop(&self) {
- unsafe {
- *(self.i) = false;
- }
+ *(self.i) = false;
}
}
enum option<T> { none, some(T), }
-fn sink(res: option<close_res>) { }
+fn sink(_res: option<close_res>) { }
pub fn main() {
let c = @mut true;
fn f() { let x: () = (); return x; }
-pub fn main() { let x = f(); }
+pub fn main() { let _x = f(); }
task::spawn(|| die() );
let (p, c) = comm::stream::<()>();
loop {
- // Sending and receiving here because these actions yield,
+ // Sending and receiving here because these actions deschedule,
// at which point our child can kill us.
c.send(());
p.recv();
// The above comment no longer makes sense but I'm
// reluctant to remove a linked failure test case.
- task::yield();
+ task::deschedule();
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::task;
struct test {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
-
// tests that ctrl's type gets inferred properly
struct Command<K, V> {
key: K,
}
fn cache_server<K:Send,V:Send>(c: Chan<Chan<Command<K, V>>>) {
- let (ctrl_port, ctrl_chan) = stream();
+ let (_ctrl_port, ctrl_chan) = stream();
c.send(ctrl_chan);
}
pub fn main() { }
match none::<int> {
some::<int>(_) => {
- for i in c.iter() {
+ for _i in c.iter() {
info!(a);
let a = 17;
b.push(a);
fn uhoh<T>(v: ~[clam<T>]) {
match v[1] {
- a::<T>(ref t, ref u) => { info!("incorrect"); info!(u); fail!(); }
+ a::<T>(ref _t, ref u) => { info!("incorrect"); info!(u); fail!(); }
b::<T> => { info!("correct"); }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test - FIXME(#8538) some kind of problem linking induced by extern "C" fns that I do not understand
// xfail-fast - windows doesn't like this
// Smallest hello world with no runtime
task::spawn(|| x(~"hello from second spawned fn", 66) );
task::spawn(|| x(~"hello from third spawned fn", 67) );
let mut i: int = 30;
- while i > 0 { i = i - 1; info!("parent sleeping"); task::yield(); }
+ while i > 0 { i = i - 1; info!("parent sleeping"); task::deschedule(); }
}
Arnold.
*/
-use std::comm::*;
use std::task;
type ctx = Chan<int>;
-fn iotask(cx: &ctx, ip: ~str) {
+fn iotask(_cx: &ctx, ip: ~str) {
assert_eq!(ip, ~"localhost");
}
pub fn main() {
- let (p, ch) = stream::<int>();
+ let (_p, ch) = stream::<int>();
task::spawn(|| iotask(&ch, ~"localhost") );
}
use std::io::WriterUtil;
use std::io;
use std::os;
-use std::uint;
pub fn main() {
let dir = tempfile::mkdtemp(&Path("."), "").unwrap();
// xfail-fast
use std::uint;
-use std::vec;
pub trait plus {
fn plus(&self) -> int;
*a = 3;
}
+#[fixed_stack_segment] #[inline(never)]
unsafe fn run() {
assert!(debug_static_mut == 3);
debug_static_mut = 4;
// This tests for issue #163
let ff: ~str = ~"abc";
- let a: ~str = ff + ~"ABC" + ff;
- let b: ~str = ~"ABC" + ff + ~"ABC";
+ let a: ~str = ff + "ABC" + ff;
+ let b: ~str = ~"ABC" + ff + "ABC";
info!(a.clone());
info!(b.clone());
assert_eq!(a, ~"abcABCabc");
extern mod extra;
-use std::str;
-
pub fn main() {
// Make sure we properly handle repeated self-appends.
let mut a: ~str = ~"A";
}
pub fn main() {
- let x = Bar { a: 2, b: 3 };
+ let _x = Bar { a: 2, b: 3 };
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
struct S { f0: ~str, f1: int }
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
struct S { f0: ~str, f1: ~str }
pub fn main() {
}
}
+#[fixed_stack_segment] #[inline(never)]
fn test1() {
unsafe {
let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa_u64,
}
#[cfg(target_arch = "x86_64")]
+#[fixed_stack_segment]
+#[inline(never)]
fn test2() {
unsafe {
let f = Floats { a: 1.234567890e-15_f64,
// Issue #5041 - avoid overlapping memcpy when src and dest of a swap are the same
use std::ptr;
-use std::util;
pub fn main() {
let mut test = TestDescAndFn {
}
pub fn main() {
- test(fmt!("hello %d friends and %s things", 10, ~"formatted"),
+ test(fmt!("hello %d friends and %s things", 10, "formatted"),
~"hello 10 friends and formatted things");
test(fmt!("test"), ~"test");
test(fmt!("%i", 2), ~"2");
test(fmt!("%i", -1), ~"-1");
test(fmt!("%u", 10u), ~"10");
- test(fmt!("%s", ~"test"), ~"test");
+ test(fmt!("%s", "test"), ~"test");
test(fmt!("%b", true), ~"true");
test(fmt!("%b", false), ~"false");
test(fmt!("%c", 'A'), ~"A");
test(fmt!("%10d", 500), ~" 500");
test(fmt!("%10d", -500), ~" -500");
test(fmt!("%10u", 500u), ~" 500");
- test(fmt!("%10s", ~"test"), ~" test");
+ test(fmt!("%10s", "test"), ~" test");
test(fmt!("%10b", true), ~" true");
test(fmt!("%10x", 0xff_u), ~" ff");
test(fmt!("%10X", 0xff_u), ~" FF");
test(fmt!("%-10d", 500), ~"500 ");
test(fmt!("%-10d", -500), ~"-500 ");
test(fmt!("%-10u", 500u), ~"500 ");
- test(fmt!("%-10s", ~"test"), ~"test ");
+ test(fmt!("%-10s", "test"), ~"test ");
test(fmt!("%-10b", true), ~"true ");
test(fmt!("%-10x", 0xff_u), ~"ff ");
test(fmt!("%-10X", 0xff_u), ~"FF ");
test(fmt!("%.d", 10), ~"10");
test(fmt!("%.d", -10), ~"-10");
test(fmt!("%.u", 10u), ~"10");
- test(fmt!("%.s", ~"test"), ~"");
+ test(fmt!("%.s", "test"), ~"");
test(fmt!("%.x", 127u), ~"7f");
test(fmt!("%.o", 10u), ~"12");
test(fmt!("%.t", 3u), ~"11");
test(fmt!("%.0d", 10), ~"10");
test(fmt!("%.0d", -10), ~"-10");
test(fmt!("%.0u", 10u), ~"10");
- test(fmt!("%.0s", ~"test"), ~"");
+ test(fmt!("%.0s", "test"), ~"");
test(fmt!("%.0x", 127u), ~"7f");
test(fmt!("%.0o", 10u), ~"12");
test(fmt!("%.0t", 3u), ~"11");
test(fmt!("%.1d", 10), ~"10");
test(fmt!("%.1d", -10), ~"-10");
test(fmt!("%.1u", 10u), ~"10");
- test(fmt!("%.1s", ~"test"), ~"t");
+ test(fmt!("%.1s", "test"), ~"t");
test(fmt!("%.1x", 127u), ~"7f");
test(fmt!("%.1o", 10u), ~"12");
test(fmt!("%.1t", 3u), ~"11");
test(fmt!("%.5d", 10), ~"00010");
test(fmt!("%.5d", -10), ~"-00010");
test(fmt!("%.5u", 10u), ~"00010");
- test(fmt!("%.5s", ~"test"), ~"test");
+ test(fmt!("%.5s", "test"), ~"test");
test(fmt!("%.5x", 127u), ~"0007f");
test(fmt!("%.5o", 10u), ~"00012");
test(fmt!("%.5t", 3u), ~"00011");
test(fmt!("%05f", 5.82), ~"05.82");
// 0-padding a string is undefined but glibc does this:
- test(fmt!("%05s", ~"test"), ~" test");
+ test(fmt!("%05s", "test"), ~" test");
test(fmt!("%05c", 'A'), ~" A");
test(fmt!("%05b", true), ~" true");
// Left-justify overrides 0-padding
test(fmt!("%-05X", 127u), ~"7F ");
test(fmt!("%-05o", 10u), ~"12 ");
test(fmt!("%-05t", 3u), ~"11 ");
- test(fmt!("%-05s", ~"test"), ~"test ");
+ test(fmt!("%-05s", "test"), ~"test ");
test(fmt!("%-05c", 'A'), ~"A ");
test(fmt!("%-05b", true), ~"true ");
test(fmt!("%-05f", 5.82), ~"5.82 ");
test(fmt!("%06.5d", 10), ~" 00010");
test(fmt!("%06.5d", -10), ~"-00010");
test(fmt!("%06.5u", 10u), ~" 00010");
- test(fmt!("%06.5s", ~"test"), ~" test");
+ test(fmt!("%06.5s", "test"), ~" test");
test(fmt!("%06.5c", 'A'), ~" A");
test(fmt!("%06.5x", 127u), ~" 0007f");
test(fmt!("%06.5X", 127u), ~" 0007F");
assert_eq!(concat_idents!(asd, f_f, dsa), ~"<.<");
assert!(stringify!(use_mention_distinction) ==
- ~"use_mention_distinction");
+ "use_mention_distinction");
}
assert_eq!(line!(), 23);
//assert!((col!() == 11));
assert_eq!(indirect_line!(), 25);
- assert!((file!().to_owned().ends_with(~"syntax-extension-source-utils.rs")));
+ assert!((file!().to_owned().ends_with("syntax-extension-source-utils.rs")));
assert_eq!(stringify!((2*3) + 5).to_owned(), ~"( 2 * 3 ) + 5");
assert!(include!("syntax-extension-source-utils-files/includeme.fragment").to_owned()
== ~"victory robot 6");
assert!(
include_str!("syntax-extension-source-utils-files/includeme.fragment").to_owned()
- .starts_with(~"/* this is for "));
+ .starts_with("/* this is for "));
assert!(
include_bin!("syntax-extension-source-utils-files/includeme.fragment")
[1] == (42 as u8)); // '*'
// The Windows tests are wrapped in an extra module for some reason
- assert!((m1::m2::where_am_i().ends_with(~"m1::m2")));
+ assert!((m1::m2::where_am_i().ends_with("m1::m2")));
}
fn foo() {
- fn zed(z: bar) { }
+ fn zed(_z: bar) { }
enum bar { nil, }
fn baz() { zed(nil); }
}
extern mod extra;
use std::comm::Chan;
-use std::comm::Port;
use std::comm;
use std::task;
pub fn main() {
let (p, ch) = comm::stream();
- let child = task::spawn(|| start(&ch) );
+ let _child = task::spawn(|| start(&ch) );
let c = p.recv();
c.send(~"A");
c.send(~"B");
- task::yield();
+ task::deschedule();
}
use std::task;
fn start(c: &comm::Chan<comm::Chan<int>>) {
- let (p, ch) = comm::stream();
+ let (_p, ch) = comm::stream();
c.send(ch);
}
pub fn main() {
let (p, ch) = comm::stream();
- let child = task::spawn(|| start(&ch) );
- let c = p.recv();
+ let _child = task::spawn(|| start(&ch) );
+ let _c = p.recv();
}
pub fn main() { test00(); }
-fn start(task_number: int) { info!("Started / Finished task."); }
+fn start(_task_number: int) { info!("Started / Finished task."); }
fn test00() {
let i: int = 0;
// Sleep long enough for the task to finish.
let mut i = 0;
while i < 10000 {
- task::yield();
+ task::deschedule();
i += 1;
}
pub fn main() {
info!("Check that we don't deadlock.");
- let (p, ch) = comm::stream();
+ let (_p, ch) = comm::stream();
task::try(|| start(&ch, 0, 10) );
info!("Joined task");
}
// Read from spawned tasks...
let mut sum = 0;
- for r in results.iter() {
+ for _r in results.iter() {
i = 0;
while i < number_of_messages {
let value = po.recv();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
use std::comm;
pub fn main() { test00(); }
pub fn main() { test00(); }
fn test00() {
- let r: int = 0;
+ let _r: int = 0;
let mut sum: int = 0;
let (p, c) = comm::stream();
let number_of_messages: int = 1000;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
use std::comm::SharedChan;
use std::comm;
// xfail-fast
+#[allow(dead_assignment)];
+
extern mod extra;
use std::comm;
}
fn supervised() {
- // Yield to make sure the supervisor joins before we
+ // Deschedule to make sure the supervisor joins before we
// fail. This is currently not needed because the supervisor
// runs first, but I can imagine that changing.
error!("supervised task=%?", 0);
- task::yield();
+ task::deschedule();
fail!();
}
use std::task;
fn supervised() {
- // Yield to make sure the supervisor joins before we fail. This is
+ // Deschedule to make sure the supervisor joins before we fail. This is
// currently not needed because the supervisor runs first, but I can
// imagine that changing.
- task::yield();
+ task::deschedule();
fail!();
}
task::spawn(|| child(~"Hello") );
}
-fn child(s: ~str) {
+fn child(_s: ~str) {
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::ptr;
use std::task;
use std::task;
-fn test_break() { loop { let x: @int = break; } }
+fn test_break() { loop { let _x: @int = break; } }
-fn test_cont() { let mut i = 0; while i < 1 { i += 1; let x: @int = loop; } }
+fn test_cont() { let mut i = 0; while i < 1 { i += 1; let _x: @int = loop; } }
-fn test_ret() { let x: @int = return; }
+fn test_ret() { let _x: @int = return; }
fn test_fail() {
- fn f() { let x: @int = fail!(); }
+ fn f() { let _x: @int = fail!(); }
task::try(|| f() );
}
fn test_fail_indirect() {
fn f() -> ! { fail!(); }
- fn g() { let x: @int = f(); }
+ fn g() { let _x: @int = f(); }
task::try(|| g() );
}
assert_eq!(i.g(), 10);
}
-fn welp<T>(i: int, x: &T) -> int {
+fn welp<T>(i: int, _x: &T) -> int {
i.g()
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::cmp::{Eq, Ord};
+use std::cmp::Eq;
use std::num::NumCast;
pub trait NumExt: Eq + Num + NumCast {}
impl ::base::HasNew<Foo> for Foo {
fn new() -> Foo {
- unsafe { println("Foo"); }
+ println("Foo");
Foo { dummy: () }
}
}
impl ::base::HasNew<Bar> for Bar {
fn new() -> Bar {
- unsafe { io::println("Bar"); }
+ io::println("Bar");
Bar { dummy: () }
}
}
}
pub fn main() {
- let f: base::Foo = base::HasNew::new::<base::Foo, base::Foo>();
- let b: base::Bar = base::HasNew::new::<base::Bar, base::Bar>();
+ let _f: base::Foo = base::HasNew::new::<base::Foo, base::Foo>();
+ let _b: base::Bar = base::HasNew::new::<base::Bar, base::Bar>();
}
assert!((~[2, 3, 4]).to_str() == ~"[2, 3, 4]");
fn indirect<T:to_str>(x: T) -> ~str {
- x.to_str() + ~"!"
+ x.to_str() + "!"
}
assert!(indirect(~[10, 20]) == ~"[10, 20]!");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
trait Foo {
fn foo(&self, mut v: int) { v = 1; }
pub mod b {
pub type t = int;
- pub fn foo() { let x: t = 10; }
+ pub fn foo() { let _x: t = 10; }
}
}
// xfail-fast
-fn p_foo<T>(pinned: T) { }
-fn s_foo<T>(shared: T) { }
-fn u_foo<T:Send>(unique: T) { }
+fn p_foo<T>(_pinned: T) { }
+fn s_foo<T>(_shared: T) { }
+fn u_foo<T:Send>(_unique: T) { }
struct r {
i: int,
while lo_ < hi { it(lo_); lo_ += 1u; }
}
-fn create_index<T>(index: ~[S<T>], hash_fn: extern fn(T) -> uint) {
- range_(0u, 256u, |_i| { let bucket: ~[T] = ~[]; } )
+fn create_index<T>(_index: ~[S<T>], _hash_fn: extern fn(T) -> uint) {
+ do range_(0u, 256u) |_i| {
+ let _bucket: ~[T] = ~[];
+ }
}
pub fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
fn f() {
let x = 10; let mut y = 11;
// -*- rust -*-
-pub fn main() { let x: uint = 10 as uint; }
+pub fn main() { let _x: uint = 10 as uint; }
let c = 1;
let c_neg: i32 = -c;
- error!(b_neg);
+ error!(c_neg);
let d = 1;
let d_neg: i64 = -d;
- error!(b_neg);
+ error!(d_neg);
let e = 1;
let e_neg: int = -e;
- error!(b_neg);
+ error!(e_neg);
// intentional overflows
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let i = ~1;
let mut j = ~2;
pub fn main() {
enum t { t1(int), t2(int), }
- let x = ~t1(10);
+ let _x = ~t1(10);
/*alt *x {
t1(a) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
+
use std::sys;
pub fn main() {
- unsafe {
- let i = ~@1;
- let j = ~@2;
- let rc1 = sys::refcount(*i);
- let j = i.clone();
- let rc2 = sys::refcount(*i);
- error!("rc1: %u rc2: %u", rc1, rc2);
- assert_eq!(rc1 + 1u, rc2);
- }
+ let i = ~@1;
+ let j = ~@2;
+ let rc1 = sys::refcount(*i);
+ let j = i.clone();
+ let rc2 = sys::refcount(*i);
+ error!("rc1: %u rc2: %u", rc1, rc2);
+ assert_eq!(rc1 + 1u, rc2);
}
let _: ~int;
}
-fn f(i: ~int) -> ~int {
+fn f(_i: ~int) -> ~int {
fail!();
}
// except according to those terms.
pub fn main() {
- let x = ~~[0,0,0,0,0];
+ let _x = ~~[0,0,0,0,0];
}
// except according to those terms.
pub fn main() {
- let i = ~100;
+ let _i = ~100;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
+
pub fn main() {
let i = ~100;
let j = ~200;
pub fn main() {
let loop_: ~EventLoop = ~UvEventLoop { uvio: 0 } as ~EventLoop;
- let loop2_ = loop_;
-}
\ No newline at end of file
+ let _loop2_ = loop_;
+}
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.i) = *(self.i) + 1;
- }
+ *(self.i) = *(self.i) + 1;
}
}
pub fn main() {
let i = @mut 0;
{
- let j = ~r(i);
+ let _j = ~r(i);
}
assert_eq!(*i, 1);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
-
pub fn main() {
let (p, c) = stream();
c.send(~100);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(unused_variable)];
+#[allow(dead_assignment)];
// -*- rust -*-
fn f(u: ()) { return u; }
-fn good(a: &int) {
+fn good(_a: &int) {
}
// unnamed argument &int is now parse x: &int
-fn called(f: &fn(&int)) {
+fn called(_f: &fn(&int)) {
}
pub fn main() {
-called(good);
+ called(good);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
fn id(x: bool) -> bool { x }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(path_statement)];
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
fn id(x: bool) -> bool { x }
// except according to those terms.
pub fn main() {
- let x = ~1;
+ let _x = ~1;
let lam_move: @fn() = || {};
lam_move();
}
// Issue Name: Unused move causes a crash
// Abstract: zero-fill to block after drop
+#[allow(path_statement)];
+
pub fn main()
{
let y = ~1;
use std::task;
fn f() {
- let a = @0;
+ let _a = @0;
fail!();
}
}
fn f() {
- let c = complainer(@0);
+ let _c = complainer(@0);
fail!();
}
use std::task;
fn f() {
- let a = ~0;
+ let _a = ~0;
fail!();
}
fn foo<T>(o: myoption<T>) -> int {
let mut x: int = 5;
- match o { none::<T> => { } some::<T>(t) => { x += 1; } }
+ match o {
+ none::<T> => { }
+ some::<T>(_t) => { x += 1; }
+ }
return x;
}
fn foo<T>(o: myoption<T>) -> int {
let mut x: int;
- match o { none::<T> => { fail!(); } some::<T>(t) => { x = 5; } }
+ match o {
+ none::<T> => { fail!(); }
+ some::<T>(_t) => { x = 5; }
+ }
return x;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
#[no_std];
extern mod std;
extern mod zed(name = "std");
extern mod extra;
use std::str;
-use std::vec;
pub fn main() {
// Chars of 1, 2, 3, and 4 bytes
assert!((str::is_utf8(s.as_bytes())));
// invalid prefix
- assert!((!str::is_utf8(~[0x80_u8])));
+ assert!((!str::is_utf8([0x80_u8])));
// invalid 2 byte prefix
- assert!((!str::is_utf8(~[0xc0_u8])));
- assert!((!str::is_utf8(~[0xc0_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xc0_u8])));
+ assert!((!str::is_utf8([0xc0_u8, 0x10_u8])));
// invalid 3 byte prefix
- assert!((!str::is_utf8(~[0xe0_u8])));
- assert!((!str::is_utf8(~[0xe0_u8, 0x10_u8])));
- assert!((!str::is_utf8(~[0xe0_u8, 0xff_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xe0_u8])));
+ assert!((!str::is_utf8([0xe0_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xe0_u8, 0xff_u8, 0x10_u8])));
// invalid 4 byte prefix
- assert!((!str::is_utf8(~[0xf0_u8])));
- assert!((!str::is_utf8(~[0xf0_u8, 0x10_u8])));
- assert!((!str::is_utf8(~[0xf0_u8, 0xff_u8, 0x10_u8])));
- assert!((!str::is_utf8(~[0xf0_u8, 0xff_u8, 0xff_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xf0_u8])));
+ assert!((!str::is_utf8([0xf0_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xf0_u8, 0xff_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xf0_u8, 0xff_u8, 0xff_u8, 0x10_u8])));
let mut stack = ~"a×c€";
assert_eq!(stack.pop_char(), '€');
pub fn main() {
// This just tests whether the vec leaks its members.
- let pvec: ~[@Pair] =
+ let _pvec: ~[@Pair] =
~[@Pair{x: 1, y: 2}, @Pair{x: 3, y: 4}, @Pair{x: 5, y: 6}];
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let a = ~[1, 2, 3, 4, 5];
let mut b = ~[a.clone(), a.clone()];
assert_eq!(b, 2);
assert!(tail.is_empty());
}
- ([..tail], _) => fail!()
+ ([.._tail], _) => fail!()
}
}
#[unsafe_destructor]
impl Drop for foo {
fn drop(&self) {
- unsafe {
- *self.x += 1;
- }
+ *self.x += 1;
}
}
assert!(tail[1].string == ~"baz");
match tail {
- [Foo { _ }, _, Foo { _ }, ..tail] => {
+ [Foo { _ }, _, Foo { _ }, .. _tail] => {
::std::util::unreachable();
}
[Foo { string: ref a }, Foo { string: ref b }] => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main() { let quux: @~[uint] = @~[]; }
+pub fn main() { let _quux: @~[uint] = @~[]; }
break; }
}
-fn evil_lincoln() { let evil = info!("lincoln"); }
+fn evil_lincoln() { let _evil = info!("lincoln"); }
pub fn main() {
strange();
-pub fn main() { let x: int = 10; while x == 10 && x == 11 { let y = 0xf00; } }
+pub fn main() { let x: int = 10; while x == 10 && x == 11 { let _y = 0xf00; } }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main() {
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+pub fn main() {
let mut y: int = 42;
let mut z: int = 42;
let mut x: int;
info!(i);
i = i + 1;
if i == 95 {
- let v: ~[int] =
+ let _v: ~[int] =
~[1, 2, 3, 4, 5]; // we check that it is freed by break
info!("breaking");
pub type LPVOID = uint;
pub type BOOL = u8;
+#[cfg(target_os = "win32")]
mod kernel32 {
use super::{HANDLE, DWORD, SIZE_T, LPVOID, BOOL};
- #[cfg(target_os = "win32")]
#[abi = "stdcall"]
extern "stdcall" {
pub fn GetProcessHeap() -> HANDLE;
#[cfg(target_os = "win32")]
+#[fixed_stack_segment]
pub fn main() {
let heap = unsafe { kernel32::GetProcessHeap() };
let mem = unsafe { kernel32::HeapAlloc(heap, 0u32, 100u32) };
// xfail-fast
extern mod xcrate_unit_struct;
-use std::util;
-
static s1: xcrate_unit_struct::Struct = xcrate_unit_struct::Struct;
static s2: xcrate_unit_struct::Unit = xcrate_unit_struct::Unit;
static s3: xcrate_unit_struct::Unit =
builder.future_result(|r| { result = Some(r); });
builder.spawn(child);
error!("1");
- task::yield();
+ task::deschedule();
error!("2");
- task::yield();
+ task::deschedule();
error!("3");
result.unwrap().recv();
}
fn child() {
- error!("4"); task::yield(); error!("5"); task::yield(); error!("6");
+ error!("4"); task::deschedule(); error!("5"); task::deschedule(); error!("6");
}
builder.future_result(|r| { result = Some(r); });
builder.spawn(child);
error!("1");
- task::yield();
+ task::deschedule();
result.unwrap().recv();
}
pub fn main() {
let mut i: int = 0;
- while i < 100 { i = i + 1; error!(i); task::yield(); }
+ while i < 100 { i = i + 1; error!(i); task::deschedule(); }
}
+++ /dev/null
-// Copyright 2012 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.
-
-// In this case, the code should compile and should
-// succeed at runtime
-
-use std::vec;
-
-fn enum_chars(start: u8, end: u8) -> ~[char] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i as char); i += 1u as u8; }
- return r;
-}
-
-fn enum_uints(start: uint, end: uint) -> ~[uint] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i); i += 1u; }
- return r;
-}
-
-pub fn main() {
- let a = 'a' as u8;
- let j = 'j' as u8;
- let k = 1u;
- let l = 10u;
- let chars = enum_chars(a, j);
- let ints = enum_uints(k, l);
-
- let ps = vec::zip(chars, ints);
-
- assert_eq!(ps.head(), &('a', 1u));
- assert_eq!(ps.last(), &(j as char, 10u));
-}