[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
-* text=auto
+* text eol=lf
*.cpp rust
*.h rust
*.rs rust
src/rt/vg/* -whitespace
src/rt/linenoise/* -whitespace
src/rt/jemalloc/**/* -whitespace
-src/rt/jemalloc/include/jemalloc/jemalloc.h.in text eol=lf
-src/rt/jemalloc/include/jemalloc/jemalloc_defs.h.in text eol=lf
-src/rt/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in text eol=lf
--- /dev/null
+% Rust Packaging Tutorial
+
+# Introduction
+
+Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to
+package up your Rust code and share it with other people. This tutorial will
+get you started on all of the concepts and commands you need to give the gift
+of Rust code to someone else.
+
+## Installing External Packages
+
+First, let's try to use an external package somehow. I've made a sample package
+called `hello` to demonstrate how to do so. Here's how `hello` is used:
+
+~~~~
+extern mod hello;
+
+fn main() {
+ hello::world();
+}
+~~~~
+
+Easy! But if you try to compile this, you'll get an error:
+
+~~~~ {.notrust}
+$ rustc main.rs
+main.rs:1:0: 1:17 error: can't find crate for `hello`
+main.rs:1 extern mod hello;
+ ^~~~~~~~~~~~~~~~~
+
+~~~~
+
+This makes sense, as we haven't gotten it from anywhere yet! Luckily for us,
+`rustpkg` has an easy way to fetch others' code: the `install` command. It's
+used like this:
+
+~~~ {.notrust}
+$ rustpkg install pkg_id
+~~~
+
+This will install a package named 'pkg_id' into your current Rust environment.
+I called it 'pkg_id' in this example because `rustpkg` calls this a 'package
+identifier.' When using it with an external package like this, it's often a
+URI fragment. You see, Rust has no central authority for packages. You can
+build your own `hello` library if you want, and that's fine. We'd both host
+them in different places and different projects would rely on whichever version
+they preferred.
+
+To install the `hello` library, simply run this in your terminal:
+
+~~~ {.notrust}
+$ rustpkg install github.com/steveklabnik/hello
+~~~
+
+You should see a message that looks like this:
+
+~~~ {.notrust}
+note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust
+~~~
+
+Now, compiling our example should work:
+
+~~~ {.notrust}
+$ rustc main.rs
+$ ./main
+Hello, world.
+~~~
+
+Simple! That's all it takes.
+
+## Workspaces
+
+Before we can talk about how to make packages of your own, you have to
+understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply
+a directory that has certain sub-directories that `rustpkg` expects. Different
+Rust projects will go into different workspaces.
+
+A workspace consists of any directory that has the following
+directories:
+
+* `src`: The directory where all the source code goes.
+* `build`: This directory contains all of the build output.
+* `lib`: The directory where any libraries distributed with the package go.
+* `bin`: This directory holds any binaries distributed with the package.
+
+There are also default file names you'll want to follow as well:
+
+* `main.rs`: A file that's going to become an executable.
+* `lib.rs`: A file that's going to become a library.
+
+## Building your own Package
+
+Now that you've got workspaces down, let's build your own copy of `hello`. Go
+to wherever you keep your personal projects, and let's make all of the
+directories we'll need. I'll refer to this personal project directory as
+`~/src` for the rest of this tutorial.
+
+### Creating our workspace
+
+~~~ {.notrust}
+$ cd ~/src
+$ mkdir -p hello/src/hello
+$ cd hello
+~~~
+
+Easy enough! Let's do one or two more things that are nice to do:
+
+~~~ {.notrust}
+$ git init .
+$ cat > README.md
+# hello
+
+A simple package for Rust.
+
+## Installation
+
+```
+$ rustpkg install github.com/YOUR_USERNAME/hello
+```
+^D
+$ cat > .gitignore
+.rust
+build
+^D
+$ git commit -am "Initial commit."
+~~~
+
+If you're not familliar with the `cat >` idiom, it will make files with the
+text you type inside. Control-D (`^D`) ends the text for the file.
+
+Anyway, we've got a README and a `.gitignore`. Let's talk about that
+`.gitignore` for a minute: we are ignoring two directories, `build` and
+`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't
+want to check those into a repository. `.rust` is a directory that `rustpkg`
+uses to keep track of its own settings, as well as the source code of any other
+external packages that this workspace uses. This is where that `rustpkg
+install` puts all of its files. Those are also not to go into our repository,
+so we ignore it all as well.
+
+Next, let's add a source file:
+
+~~~
+#[desc = "A hello world Rust package."];
+#[license = "MIT"];
+
+pub fn world() {
+ println("Hello, world.");
+}
+~~~
+
+Put this into `src/hello/lib.rs`. Let's talk about each of these attributes:
+
+### Crate attributes for packages
+
+`license` is equally simple: the license we want this code to have. I chose MIT
+here, but you should pick whatever license makes the most sense for you.
+
+`desc` is a description of the package and what it does. This should just be a
+sentence or two.
+
+### Building your package
+
+Building your package is simple:
+
+~~~ {.notrust}
+$ rustpkg build hello
+~~~
+
+This will compile `src/hello/lib.rs` into a library. After this process
+completes, you'll want to check out `build`:
+
+~~~ {.notrust}
+$ ls build/x86_64-unknown-linux-gnu/hello/
+libhello-ed8619dad9ce7d58-0.1.0.so
+~~~
+
+This directory naming structure is called a 'build triple,' and is because I'm
+on 64 bit Linux. Yours may differ based on platform.
+
+You'll also notice that `src/hello/lib.rs` turned into
+`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the
+library name, a hash of its content, and the version.
+
+Now that your library builds, you'll want to commit:
+
+~~~ {.notrust}
+$ git add src
+$ git commit -m "Adding source code."
+~~~
+
+If you're using GitHub, after creating the project, do this:
+
+~~~ {.notrust}
+$ git remote add origin git@github.com:YOUR_USERNAME/hello.git
+$ git push origin -u master
+~~~
+
+Now you can install and use it! Go anywhere else in your filesystem:
+
+~~~ {.notrust}
+$ cd ~/src/foo
+$ rustpkg install github/YOUR_USERNAME/hello
+WARNING: The Rust package manager is experimental and may be unstable
+note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust
+~~~
+
+That's it!
+
+## More resources
+
+There's a lot more going on with `rustpkg`, this is just to get you started.
+Check out [the rustpkg manual](rustpkg.html) for the full details on how to
+customize `rustpkg`.
+
+A tag was created on GitHub specifically for `rustpkg`-related issues. You can
+[see all the Issues for rustpkg
+here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open),
+with bugs as well as new feature plans. `rustpkg` is still under development,
+and so may be a bit flaky at the moment.
+
+You may also want to check out [this blog
+post](http://tim.dreamwidth.org/1820526.html), which contains some of the early
+design decisions and justifications.
* [The foreign function interface][ffi]
* [Containers and iterators](tutorial-container.html)
* [Error-handling and Conditions](tutorial-conditions.html)
+* [Packaging up Rust code](rustpkg)
There is further documentation on the [wiki], however those tend to be even more out of date as this document.
[tasks]: tutorial-tasks.html
[macros]: tutorial-macros.html
[ffi]: tutorial-ffi.html
+[rustpkg]: tutorial-rustpkg.html
[wiki]: https://github.com/mozilla/rust/wiki/Docs
available at <\fBhttps://www.rust-lang.org\fR>. It provides commands to build,
install and test Rust programs.
+\fBrustpkg\fR is still a work in progress. See \fBdoc/rustpkg.md\fR in the Rust source distribution for future plans.
+
.SH COMMANDS
.TP
Builds the specified target, and all its dependencies, and then installs the
build products into the \fIlib\fR and \fIbin\fR directories of their respective
workspaces.
-.TP
-\fBtest\fR
-Builds the module called \fItest.rs\fR in the specified workspace, and then runs
-the resulting executable in test mode.
.SS "BUILD COMMAND"
Examples:
- $ rustpkg install git://github.com/mozilla/servo.git#1.2
+ $ rustpkg install github.com/mozilla/servo.git#1.2
$ rustpkg install rust-glfw
-.SS "TEST COMMAND"
-
- rustpkg test \fI[pkgname]\fR
-
-The test command is a shortcut for the command line:
-
- $ rustc --test <filename> -o <filestem>test~ && ./<filestem>test~
-
-Note the suffix on the output filename (the word "test" followed by a tilde),
-which should ensure the file does not clash with a user-generated files.
-
.SH "ENVIRONMENT"
.TP
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
.SH "AUTHOR"
-See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare
+See \fBAUTHORS.txt\fR in the Rust source distribution. Graydon Hoare
<\fIgraydon@mozilla.com\fR> is the project leader.
.SH "COPYRIGHT"
CFG_GCCISH_CFLAGS += -O2
endif
+# The soname thing is for supporting a statically linked jemalloc.
+# see https://blog.mozilla.org/jseward/2012/06/05/valgrind-now-supports-jemalloc-builds-directly/
ifdef CFG_VALGRIND
CFG_VALGRIND += --error-exitcode=100 \
+ --soname-synonyms=somalloc=NONE \
--quiet \
--suppressions=$(CFG_SRC_DIR)src/etc/x86.supp \
$(OS_SUPP)
_id: uint,
cnt: uint,
f: &fn(&mut Encoder)) {
- // enums are encoded as strings or vectors:
+ // enums are encoded as strings or objects
// Bunny => "Bunny"
- // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]]
-
+ // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
if cnt == 0 {
self.wr.write_str(escape_str(name));
} else {
- self.wr.write_char('[');
+ self.wr.write_char('{');
+ self.wr.write_str("\"variant\"");
+ self.wr.write_char(':');
self.wr.write_str(escape_str(name));
self.wr.write_char(',');
+ self.wr.write_str("\"fields\"");
+ self.wr.write_str(":[");
f(self);
- self.wr.write_char(']');
+ self.wr.write_str("]}");
}
}
debug!("read_enum_variant(names=%?)", names);
let name = match self.stack.pop() {
String(s) => s,
- List(list) => {
- for v in list.move_rev_iter() {
- self.stack.push(v);
- }
- match self.stack.pop() {
- String(s) => s,
- value => fail!("invalid variant name: %?", value),
+ Object(o) => {
+ let n = match o.find(&~"variant").expect("invalidly encoded json") {
+ &String(ref s) => s.clone(),
+ _ => fail!("invalidly encoded json"),
+ };
+ match o.find(&~"fields").expect("invalidly encoded json") {
+ &List(ref l) => {
+ for field in l.rev_iter() {
+ self.stack.push(field.clone());
+ }
+ },
+ _ => fail!("invalidly encoded json")
}
+ n
}
ref json => fail!("invalid variant: %?", *json),
};
let mut encoder = Encoder(wr);
animal.encode(&mut encoder);
},
- ~"[\"Frog\",\"Henry\",349]"
+ ~"{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
);
assert_eq!(
do io::with_str_writer |wr| {
assert_eq!(value, Dog);
let mut decoder =
- Decoder(from_str("[\"Frog\",\"Henry\",349]").unwrap());
+ Decoder(from_str("{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}").unwrap());
let value: Animal = Decodable::decode(&mut decoder);
assert_eq!(value, Frog(~"Henry", 349));
}
#[test]
fn test_decode_map() {
- let s = ~"{\"a\": \"Dog\", \"b\": [\"Frog\", \"Henry\", 349]}";
+ let s = ~"{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\"fields\":[\"Henry\", 349]}}";
let mut decoder = Decoder(from_str(s).unwrap());
let mut map: TreeMap<~str, Animal> = Decodable::decode(&mut decoder);
reexports2: middle::resolve::ExportMap2,
item_symbols: &'self HashMap<ast::NodeId, ~str>,
discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+ non_inlineable_statics: &'self HashSet<ast::NodeId>,
link_meta: &'self LinkMeta,
cstore: @mut cstore::CStore,
encode_inlined_item: encode_inlined_item<'self>,
reexports2: middle::resolve::ExportMap2,
item_symbols: &'self HashMap<ast::NodeId, ~str>,
discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+ non_inlineable_statics: &'self HashSet<ast::NodeId>,
link_meta: &'self LinkMeta,
cstore: &'self cstore::CStore,
encode_inlined_item: encode_inlined_item<'self>,
encode_name(ecx, ebml_w, item.ident);
let elt = ast_map::path_pretty_name(item.ident, item.id as u64);
encode_path(ecx, ebml_w, path, elt);
- (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+ if !ecx.non_inlineable_statics.contains(&item.id) {
+ (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+ }
ebml_w.end_tag();
}
item_fn(_, purity, _, ref generics, _) => {
encode_inlined_item,
link_meta,
reachable,
+ non_inlineable_statics,
_
} = parms;
let type_abbrevs = @mut HashMap::new();
reexports2: reexports2,
item_symbols: item_symbols,
discrim_symbols: discrim_symbols,
+ non_inlineable_statics: non_inlineable_statics,
link_meta: link_meta,
cstore: cstore,
encode_inlined_item: encode_inlined_item,
return single_result(datumblock.to_result(bcx));
}
lit(ConstLit(lit_id)) => {
- let llval = consts::get_const_val(bcx.ccx(), lit_id);
+ let (llval, _) = consts::get_const_val(bcx.ccx(), lit_id);
return single_result(rslt(bcx, llval));
}
var(disr_val, repr) => {
return adt::trans_case(bcx, repr, disr_val);
}
range(l1, l2) => {
- return range_result(rslt(bcx, consts::const_expr(ccx, l1)),
- rslt(bcx, consts::const_expr(ccx, l2)));
+ let (l1, _) = consts::const_expr(ccx, l1);
+ let (l2, _) = consts::const_expr(ccx, l2);
+ return range_result(rslt(bcx, l1), rslt(bcx, l2));
}
vec_len(n, vec_len_eq, _) => {
return single_result(rslt(bcx, C_int(ccx, n as int)));
}
}
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
let llfn: ValueRef = do name.with_c_str |buf| {
unsafe {
return llfn;
}
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
return decl_fn(llmod, name, lib::llvm::CCallConv, ty);
}
-// Only use this if you are going to actually define the function. It's
-// not valid to simply declare a function as internal.
-pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
- let llfn = decl_cdecl_fn(llmod, name, ty);
- lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
- return llfn;
-}
-
+// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
match externs.find_equiv(&name) {
}
let f = decl_fn(llmod, name, cc, ty);
externs.insert(name.to_owned(), f);
- return f;
+ f
+}
+
+pub fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ match ccx.externs.find_equiv(&name) {
+ Some(n) => return *n,
+ None => ()
+ }
+ let f = decl_rust_fn(ccx, inputs, output, name);
+ ccx.externs.insert(name.to_owned(), f);
+ f
+}
+
+pub fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfty = type_of_rust_fn(ccx, inputs, output);
+ let llfn = decl_cdecl_fn(ccx.llmod, name, llfty);
+
+ match ty::get(output).sty {
+ // `~` pointer return values never alias because ownership is transferred
+ ty::ty_uniq(*) |
+ ty::ty_evec(_, ty::vstore_uniq) => {
+ unsafe {
+ llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
+ }
+ }
+ _ => ()
+ }
+
+ let uses_outptr = type_of::return_uses_outptr(ccx.tcx, output);
+ let offset = if uses_outptr { 2 } else { 1 };
+
+ for (i, &arg_ty) in inputs.iter().enumerate() {
+ let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
+ match ty::get(arg_ty).sty {
+ // `~` pointer parameters never alias because ownership is transferred
+ ty::ty_uniq(*) |
+ ty::ty_evec(_, ty::vstore_uniq) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
+ unsafe {
+ llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
+ }
+ }
+ _ => ()
+ }
+ }
+
+ // The out pointer will never alias with any other pointers, as the object only exists at a
+ // language level after the call. It can also be tagged with SRet to indicate that it is
+ // guaranteed to point to a usable block of memory for the type.
+ if uses_outptr {
+ unsafe {
+ let outptr = llvm::LLVMGetParam(llfn, 0);
+ llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint);
+ llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint);
+ }
+ }
+
+ llfn
+}
+
+pub fn decl_internal_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfn = decl_rust_fn(ccx, inputs, output, name);
+ lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
+ llfn
}
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
C_null(Type::opaque_box(ccx).ptr_to())
}
-pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t)
- -> ValueRef {
+pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty {
ty::ty_bare_fn(ref fn_ty) => {
- // Currently llvm_calling_convention triggers unimpl/bug on
- // Rust/RustIntrinsic, so those two are handled specially here.
- let cconv = match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
- Some(Rust) | Some(RustIntrinsic) => lib::llvm::CCallConv,
+ match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
+ Some(Rust) | Some(RustIntrinsic) => {
+ get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name)
+ }
Some(*) | None => {
let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
- c.unwrap_or(lib::llvm::CCallConv)
+ let cconv = c.unwrap_or(lib::llvm::CCallConv);
+ let llty = type_of_fn_from_ty(ccx, t);
+ get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty)
}
- };
- let llty = type_of_fn_from_ty(ccx, t);
- return get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty);
+ }
}
- ty::ty_closure(_) => {
- let llty = type_of_fn_from_ty(ccx, t);
- return get_extern_fn(&mut ccx.externs, ccx.llmod, name,
- lib::llvm::CCallConv, llty);
+ ty::ty_closure(ref f) => {
+ get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name)
}
_ => {
let llty = type_of(ccx, t);
- return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
+ get_extern_const(&mut ccx.externs, ccx.llmod, name, llty)
}
- };
+ }
}
pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
llfn,
llargs,
normal_bcx.llbb,
- get_landing_pad(bcx));
+ get_landing_pad(bcx),
+ attributes);
return (llresult, normal_bcx);
} else {
unsafe {
// field of the fn_ctxt with
pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
self_arg: self_arg,
- args: &[ast::arg],
- arg_tys: &[ty::t])
+ args: &[ast::arg])
-> ~[ValueRef] {
let _icx = push_ctxt("create_llargs_for_fn_args");
// Return an array containing the ValueRefs that we get from
// llvm::LLVMGetParam for each argument.
do vec::from_fn(args.len()) |i| {
- let arg_n = cx.arg_pos(i);
- let arg_ty = arg_tys[i];
- let llarg = unsafe {llvm::LLVMGetParam(cx.llfn, arg_n as c_uint) };
-
- match ty::get(arg_ty).sty {
- // `~` pointer parameters never alias because ownership is transferred
- ty::ty_uniq(*) |
- ty::ty_evec(_, ty::vstore_uniq) |
- ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
- unsafe {
- llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
- }
- }
- _ => ()
- }
-
- llarg
+ unsafe { llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint) }
}
}
// Set up arguments to the function.
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
- let raw_llargs = create_llargs_for_fn_args(fcx, self_arg,
- decl.inputs, arg_tys);
+ let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
// Set the fixed stack segment flag if necessary.
if attr::contains_name(attributes, "fixed_stack_segment") {
param_substs.repr(ccx.tcx));
let _icx = push_ctxt("trans_fn");
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
-
- match ty::get(output_type).sty {
- // `~` pointer return values never alias because ownership is transferred
- ty::ty_uniq(*) |
- ty::ty_evec(_, ty::vstore_uniq) => {
- unsafe {
- llvm::LLVMAddReturnAttribute(llfndecl, lib::llvm::NoAliasAttribute as c_uint);
- }
- }
- _ => ()
- }
-
trans_closure(ccx,
path.clone(),
decl,
let arg_tys = ty::ty_fn_args(ctor_ty);
- let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, arg_tys);
+ let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = fcx.entry_bcx.unwrap();
node_id: ast::NodeId,
node_type: ty::t)
-> ValueRef {
- let llfty = type_of_fn_from_ty(ccx, node_type);
- register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
+ let f = match ty::get(node_type).sty {
+ ty::ty_bare_fn(ref f) => {
+ assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+ f
+ }
+ _ => fail!("expected bare rust fn or an intrinsic")
+ };
+
+ let llfn = decl_rust_fn(ccx, f.sig.inputs, f.sig.output, sym);
+ ccx.item_symbols.insert(node_id, sym);
+
+ // FIXME #4404 android JNI hacks
+ let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
+ (*ccx.sess.building_library &&
+ ccx.sess.targ_cfg.os == session::OsAndroid));
+ if is_entry {
+ create_entry_wrapper(ccx, sp, llfn);
+ }
+ llfn
}
+// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
pub fn register_fn_llvmty(ccx: @mut CrateContext,
sp: Span,
sym: ~str,
let sym = exported_name(ccx, my_path, ty, i.attrs);
let v = match i.node {
- ast::item_static(_, m, expr) => {
+ ast::item_static(_, _, expr) => {
+ // If this static came from an external crate, then
+ // we need to get the symbol from csearch instead of
+ // using the current crate's name/version
+ // information in the hash of the symbol
+ debug!("making %s", sym);
+ let sym = match ccx.external_srcs.find(&i.id) {
+ Some(&did) => {
+ debug!("but found in other crate...");
+ csearch::get_symbol(ccx.sess.cstore, did)
+ }
+ None => sym
+ };
+
// We need the translated value here, because for enums the
// LLVM type is not fully determined by the Rust type.
- let v = consts::const_expr(ccx, expr);
+ let (v, inlineable) = consts::const_expr(ccx, expr);
ccx.const_values.insert(id, v);
- exprt = (m == ast::MutMutable || i.vis == ast::public);
+ if !inlineable {
+ debug!("%s not inlined", sym);
+ ccx.non_inlineable_statics.insert(id);
+ }
+ exprt = true;
unsafe {
let llty = llvm::LLVMTypeOf(v);
reexports2: cx.exp_map2,
item_symbols: item_symbols,
discrim_symbols: discrim_symbols,
+ non_inlineable_statics: &cx.non_inlineable_statics,
link_meta: link_meta,
cstore: cx.sess.cstore,
encode_inlined_item: ie,
Fn: ValueRef,
Args: &[ValueRef],
Then: BasicBlockRef,
- Catch: BasicBlockRef)
+ Catch: BasicBlockRef,
+ attributes: &[(uint, lib::llvm::Attribute)])
-> ValueRef {
if cx.unreachable {
return C_null(Type::i8());
debug!("Invoke(%s with arguments (%s))",
cx.val_to_str(Fn),
Args.map(|a| cx.val_to_str(*a)).connect(", "));
- B(cx).invoke(Fn, Args, Then, Catch)
-}
-
-pub fn FastInvoke(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
- Then: BasicBlockRef, Catch: BasicBlockRef) {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "FastInvoke");
- B(cx).fast_invoke(Fn, Args, Then, Catch);
+ B(cx).invoke(Fn, Args, Then, Catch, attributes)
}
pub fn Unreachable(cx: @mut Block) {
llfn: ValueRef,
args: &[ValueRef],
then: BasicBlockRef,
- catch: BasicBlockRef)
+ catch: BasicBlockRef,
+ attributes: &[(uint, lib::llvm::Attribute)])
-> ValueRef {
self.count_insn("invoke");
unsafe {
- llvm::LLVMBuildInvoke(self.llbuilder,
- llfn,
- vec::raw::to_ptr(args),
- args.len() as c_uint,
- then,
- catch,
- noname())
+ let v = llvm::LLVMBuildInvoke(self.llbuilder,
+ llfn,
+ vec::raw::to_ptr(args),
+ args.len() as c_uint,
+ then,
+ catch,
+ noname());
+ for &(idx, attr) in attributes.iter() {
+ llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+ }
+ v
}
}
- pub fn fast_invoke(&self,
- llfn: ValueRef,
- args: &[ValueRef],
- then: BasicBlockRef,
- catch: BasicBlockRef) {
- self.count_insn("fastinvoke");
- let v = self.invoke(llfn, args, then, catch);
- lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
- }
-
pub fn unreachable(&self) {
self.count_insn("unreachable");
unsafe {
use back::abi;
use driver::session;
-use lib::llvm::ValueRef;
+use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute};
use lib::llvm::llvm;
use metadata::csearch;
use middle::trans::base;
_ => {}
}
+ // A function pointer is called without the declaration available, so we have to apply
+ // any attributes with ABI implications directly to the call instruction. Right now, the
+ // only attribute we need to worry about is `sret`.
+ let mut attrs = ~[];
+ if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
+ attrs.push((1, StructRetAttribute));
+ }
+
+ // The `noalias` attribute on the return value is useful to a function ptr caller.
+ match ty::get(ret_ty).sty {
+ // `~` pointer return values never alias because ownership is transferred
+ ty::ty_uniq(*) |
+ ty::ty_evec(_, ty::vstore_uniq) => {
+ attrs.push((0, NoAliasAttribute));
+ }
+ _ => ()
+ }
+
// Invoke the actual rust fn and update bcx/llresult.
- let (llret, b) = base::invoke(bcx, llfn, llargs, []);
+ let (llret, b) = base::invoke(bcx, llfn, llargs, attrs);
bcx = b;
llresult = llret;
let ccx = bcx.ccx();
let fty = node_id_type(bcx, outer_id);
-
- let llfnty = type_of_fn_from_ty(ccx, fty);
+ let f = match ty::get(fty).sty {
+ ty::ty_closure(ref f) => f,
+ _ => fail!("expected closure")
+ };
let sub_path = vec::append_one(bcx.fcx.path.clone(),
path_name(special_idents::anon));
let s = mangle_internal_name_by_path_and_seq(ccx,
sub_path.clone(),
"expr_fn");
- let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
+ let llfn = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
// set an inline hint for all closures
set_inline_hint(llfn);
}
pub fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr])
- -> (ValueRef, ValueRef, Type) {
+ -> (ValueRef, ValueRef, Type, bool) {
unsafe {
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 unit_sz = machine::llsize_of(cx, llunitty);
let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz);
- let vs = es.map(|e| const_expr(cx, *e));
+ let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
// If the vector contains enums, an LLVM array won't work.
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs)
} else {
C_array(llunitty, vs)
};
- return (v, sz, llunitty);
+ return (v, sz, llunitty, inlineable.iter().fold(true, |a, &b| a && b));
}
}
}
}
-pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::DefId) -> ValueRef {
+pub fn get_const_val(cx: @mut CrateContext,
+ mut def_id: ast::DefId) -> (ValueRef, bool) {
let contains_key = cx.const_values.contains_key(&def_id.node);
if !ast_util::is_local(def_id) || !contains_key {
if !ast_util::is_local(def_id) {
_ => cx.tcx.sess.bug("expected a const to be an item")
}
}
- cx.const_values.get_copy(&def_id.node)
+ (cx.const_values.get_copy(&def_id.node),
+ !cx.non_inlineable_statics.contains(&def_id.node))
}
-pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
- let mut llconst = const_expr_unadjusted(cx, e);
+pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> (ValueRef, bool) {
+ let (llconst, inlineable) = const_expr_unadjusted(cx, e);
+ let mut llconst = llconst;
+ let mut inlineable = inlineable;
let ety = ty::expr_ty(cx.tcx, e);
let adjustment = cx.tcx.adjustments.find_copy(&e.id);
match adjustment {
// Don't copy data to do a deref+ref.
let llptr = match maybe_ptr {
Some(ptr) => ptr,
- None => const_addr_of(cx, llconst)
+ None => {
+ inlineable = false;
+ const_addr_of(cx, llconst)
+ }
};
match *autoref {
ty::AutoUnsafe(m) |
e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
csize, tsize));
}
- llconst
+ (llconst, inlineable)
}
-fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
+// the bool returned is whether this expression can be inlined into other crates
+// if it's assigned to a static.
+fn const_expr_unadjusted(cx: @mut CrateContext,
+ e: &ast::Expr) -> (ValueRef, bool) {
+ fn map_list(cx: @mut CrateContext,
+ exprs: &[@ast::Expr]) -> (~[ValueRef], bool) {
+ exprs.iter().map(|&e| const_expr(cx, e))
+ .fold((~[], true), |(L, all_inlineable), (val, inlineable)| {
+ (vec::append_one(L, val), all_inlineable && inlineable)
+ })
+ }
unsafe {
let _icx = push_ctxt("const_expr");
return match e.node {
- ast::ExprLit(lit) => consts::const_lit(cx, e, *lit),
+ ast::ExprLit(lit) => (consts::const_lit(cx, e, *lit), true),
ast::ExprBinary(_, b, e1, e2) => {
- let te1 = const_expr(cx, e1);
- let te2 = const_expr(cx, e2);
+ let (te1, _) = const_expr(cx, e1);
+ let (te2, _) = const_expr(cx, e2);
let te2 = base::cast_shift_const_rhs(b, te1, te2);
let ty = ty::expr_ty(cx.tcx, e1);
let is_float = ty::type_is_fp(ty);
let signed = ty::type_is_signed(ty);
- return match b {
+ return (match b {
ast::BiAdd => {
if is_float { llvm::LLVMConstFAdd(te1, te2) }
else { llvm::LLVMConstAdd(te1, te2) }
else { ConstICmp(IntUGT, te1, te2) }
}
},
- };
+ }, true)
},
ast::ExprUnary(_, u, e) => {
- let te = const_expr(cx, e);
+ let (te, _) = const_expr(cx, e);
let ty = ty::expr_ty(cx.tcx, e);
let is_float = ty::type_is_fp(ty);
- return match u {
+ return (match u {
ast::UnBox(_) |
ast::UnUniq |
ast::UnDeref => {
if is_float { llvm::LLVMConstFNeg(te) }
else { llvm::LLVMConstNeg(te) }
}
- }
+ }, true)
}
ast::ExprField(base, field, _) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
let brepr = adt::represent_type(cx, bt);
- let bv = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base);
do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| {
let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
- adt::const_get_field(cx, brepr, bv, discr, ix)
+ (adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
}
}
ast::ExprIndex(_, base, index) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
- let bv = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base);
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
const_eval::const_int(i) => i as u64,
const_eval::const_uint(u) => u,
cx.sess.span_err(e.span,
"const index-expr is out of bounds");
}
- const_get_elt(cx, arr, [iv as c_uint])
+ (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
}
ast::ExprCast(base, _) => {
let ety = ty::expr_ty(cx.tcx, e);
let llty = type_of::type_of(cx, ety);
let basety = ty::expr_ty(cx.tcx, base);
- let v = const_expr(cx, base);
- match (expr::cast_type_kind(basety),
- expr::cast_type_kind(ety)) {
+ let (v, inlineable) = const_expr(cx, base);
+ return (match (expr::cast_type_kind(basety),
+ expr::cast_type_kind(ety)) {
(expr::cast_integral, expr::cast_integral) => {
let s = ty::type_is_signed(basety) as Bool;
cx.sess.impossible_case(e.span,
"bad combination of types for cast")
}
- }
+ }, inlineable)
}
ast::ExprAddrOf(ast::MutImmutable, sub) => {
- let e = const_expr(cx, sub);
- const_addr_of(cx, e)
+ let (e, _) = const_expr(cx, sub);
+ (const_addr_of(cx, e), false)
}
ast::ExprTup(ref es) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let vals = es.map(|&e| const_expr(cx, e));
- adt::trans_const(cx, repr, 0, vals)
+ let (vals, inlineable) = map_list(cx, *es);
+ (adt::trans_const(cx, repr, 0, vals), inlineable)
}
ast::ExprStruct(_, ref fs, ref base_opt) => {
let ety = ty::expr_ty(cx.tcx, e);
do expr::with_field_tys(tcx, ety, Some(e.id))
|discr, field_tys| {
- let cs: ~[ValueRef] = field_tys.iter().enumerate()
+ let cs = field_tys.iter().enumerate()
.map(|(ix, &field_ty)| {
match fs.iter().find(|f| field_ty.ident.name == f.ident.name) {
Some(f) => const_expr(cx, (*f).expr),
None => {
match base_val {
- Some(bv) => adt::const_get_field(cx, repr, bv, discr, ix),
+ Some((bv, inlineable)) => {
+ (adt::const_get_field(cx, repr, bv, discr, ix),
+ inlineable)
+ }
None => cx.tcx.sess.span_bug(e.span, "missing struct field")
}
}
}
- }).collect();
- adt::trans_const(cx, repr, discr, cs)
+ }).to_owned_vec();
+ let (cs, inlineable) = vec::unzip(cs.move_iter());
+ (adt::trans_const(cx, repr, discr, cs),
+ inlineable.iter().fold(true, |a, &b| a && b))
}
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (v, _, _) = const_vec(cx, e, *es);
- v
+ let (v, _, _, inlineable) = const_vec(cx, e, *es);
+ (v, inlineable)
}
ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
match sub.node {
}
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (cv, sz, llunitty) = const_vec(cx, e, *es);
+ let (cv, sz, llunitty, _) = const_vec(cx, e, *es);
let llty = val_ty(cv);
let gv = do "const".with_c_str |name| {
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
llvm::LLVMSetGlobalConstant(gv, True);
SetLinkage(gv, PrivateLinkage);
let p = const_ptrcast(cx, gv, llunitty);
- C_struct([p, sz])
+ (C_struct([p, sz]), false)
}
_ => cx.sess.span_bug(e.span, "bad const-slice expr")
}
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 vs = vec::from_elem(n, const_expr(cx, elem).first());
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs)
} else {
C_array(llunitty, vs)
};
- v
+ (v, true)
}
ast::ExprPath(ref pth) => {
// Assert that there are no type parameters in this path.
Some(&ast::DefFn(def_id, _purity)) => {
if !ast_util::is_local(def_id) {
let ty = csearch::get_type(cx.tcx, def_id).ty;
- base::trans_external_path(cx, def_id, ty)
+ (base::trans_external_path(cx, def_id, ty), true)
} else {
assert!(ast_util::is_local(def_id));
- base::get_item_val(cx, def_id.node)
+ (base::get_item_val(cx, def_id.node), true)
}
}
Some(&ast::DefStatic(def_id, false)) => {
let vinfo = ty::enum_variant_with_id(cx.tcx,
enum_did,
variant_did);
- adt::trans_const(cx, repr, vinfo.disr_val, [])
+ (adt::trans_const(cx, repr, vinfo.disr_val, []), true)
}
Some(&ast::DefStruct(_)) => {
let ety = ty::expr_ty(cx.tcx, e);
let llty = type_of::type_of(cx, ety);
- C_null(llty)
+ (C_null(llty), true)
}
_ => {
cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def")
Some(&ast::DefStruct(_)) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let arg_vals = args.map(|a| const_expr(cx, *a));
- adt::trans_const(cx, repr, 0, arg_vals)
+ let (arg_vals, inlineable) = map_list(cx, *args);
+ (adt::trans_const(cx, repr, 0, arg_vals), inlineable)
}
Some(&ast::DefVariant(enum_did, variant_did, _)) => {
let ety = ty::expr_ty(cx.tcx, e);
let vinfo = ty::enum_variant_with_id(cx.tcx,
enum_did,
variant_did);
- let arg_vals = args.map(|a| const_expr(cx, *a));
- adt::trans_const(cx, repr, vinfo.disr_val, arg_vals)
+ let (arg_vals, inlineable) = map_list(cx, *args);
+ (adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
+ inlineable)
}
_ => cx.sess.span_bug(e.span, "expected a struct or variant def")
}
}
- ast::ExprParen(e) => { return const_expr(cx, e); }
+ ast::ExprParen(e) => { const_expr(cx, e) }
_ => cx.sess.span_bug(e.span,
"bad constant expression type in consts::const_expr")
};
finished_tydescs: bool,
// Track mapping of external ids to local items imported for inlining
external: HashMap<ast::DefId, Option<ast::NodeId>>,
+ // Backwards version of the `external` map (inlined items to where they
+ // came from)
+ external_srcs: HashMap<ast::NodeId, ast::DefId>,
+ // A set of static items which cannot be inlined into other crates. This
+ // will pevent in ii_item() structures from being encoded into the metadata
+ // that is generated
+ non_inlineable_statics: HashSet<ast::NodeId>,
// Cache instances of monomorphized functions
monomorphized: HashMap<mono_id, ValueRef>,
monomorphizing: HashMap<ast::DefId, uint>,
tydescs: HashMap::new(),
finished_tydescs: false,
external: HashMap::new(),
+ external_srcs: HashMap::new(),
+ non_inlineable_statics: HashSet::new(),
monomorphized: HashMap::new(),
monomorphizing: HashMap::new(),
type_use_cache: HashMap::new(),
use back::abi;
use back::link;
-use lib::llvm::{ValueRef, llvm, SetLinkage, ExternalLinkage, False};
+use lib::llvm::{ValueRef, llvm, SetLinkage, False};
use lib;
use metadata::csearch;
use middle::trans::_match;
use middle::trans::debuginfo;
use middle::trans::machine;
use middle::trans::meth;
+use middle::trans::inline;
use middle::trans::tvec;
use middle::trans::type_of;
use middle::ty::struct_fields;
ast::DefStatic(did, _) => {
let const_ty = expr_ty(bcx, ref_expr);
+ fn get_did(ccx: @mut CrateContext, did: ast::DefId)
+ -> ast::DefId {
+ if did.crate != ast::LOCAL_CRATE {
+ inline::maybe_instantiate_inline(ccx, did)
+ } else {
+ did
+ }
+ }
+
fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
-> ValueRef {
// For external constants, we don't inline.
llty.to_ref(),
buf)
};
- SetLinkage(llval, ExternalLinkage);
let extern_const_values = &mut bcx.ccx().extern_const_values;
extern_const_values.insert(did, llval);
llval
}
}
+ let did = get_did(bcx.ccx(), did);
let val = get_val(bcx, did, const_ty);
DatumBlock {
bcx: bcx,
use middle::trans::build::*;
use middle::trans::builder::noname;
use middle::trans::common::*;
-use middle::trans::llrepr::LlvmRepr;
use middle::trans::type_of::*;
use middle::trans::type_of;
use middle::ty;
}
};
+ // A function pointer is called without the declaration available, so we have to apply
+ // any attributes with ABI implications directly to the call instruction. Right now, the
+ // only attribute we need to worry about is `sret`.
let attrs;
if fn_type.sret {
attrs = &[(1, StructRetAttribute)];
special_idents::clownshoe_abi
)));
- // Compute the LLVM type that the function would have if it
- // were just a normal Rust function. This will be the type of
- // the wrappee fn.
- let llty = match ty::get(t).sty {
+ // Compute the type that the function would have if it were just a
+ // normal Rust function. This will be the type of the wrappee fn.
+ let f = match ty::get(t).sty {
ty::ty_bare_fn(ref f) => {
assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
- type_of_rust_fn(ccx, f.sig.inputs, f.sig.output)
+ f
}
_ => {
ccx.sess.bug(fmt!("build_rust_fn: extern fn %s has ty %s, \
}
};
- debug!("build_rust_fn: path=%s id=%? t=%s llty=%s",
+ debug!("build_rust_fn: path=%s id=%? t=%s",
path.repr(tcx),
id,
- t.repr(tcx),
- llty.llrepr(ccx));
+ t.repr(tcx));
- let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
+ let llfndecl = base::decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, ps);
base::trans_fn(ccx,
(*path).clone(),
decl,
// 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
+ // foreign fn does NOT use an outpointer, we will have to
// alloca some scratch space on the stack.
match foreign_outptr {
Some(llforeign_outptr) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+use lib::llvm::{AvailableExternallyLinkage, SetLinkage};
use metadata::csearch;
use middle::astencode;
use middle::trans::base::{push_ctxt, impl_self, no_self};
}
csearch::found(ast::ii_item(item)) => {
ccx.external.insert(fn_id, Some(item.id));
+ ccx.external_srcs.insert(item.id, fn_id);
ccx.stats.n_inlines += 1;
trans_item(ccx, item);
+
+ // We're bringing an external global into this crate, but we don't
+ // want to create two copies of the global. If we do this, then if
+ // you take the address of the global in two separate crates you get
+ // two different addresses. This is bad for things like conditions,
+ // but it could possibly have other adverse side effects. We still
+ // want to achieve the optimizations related to this global,
+ // however, so we use the available_externally linkage which llvm
+ // provides
+ match item.node {
+ ast::item_static(*) => {
+ let g = get_item_val(ccx, item.id);
+ SetLinkage(g, AvailableExternallyLinkage);
+ }
+ _ => {}
+ }
+
local_def(item.id)
}
csearch::found(ast::ii_foreign(item)) => {
ccx.external.insert(fn_id, Some(item.id));
+ ccx.external_srcs.insert(item.id, fn_id);
local_def(item.id)
}
csearch::found_parent(parent_id, ast::ii_item(item)) => {
ccx.external.insert(parent_id, Some(item.id));
+ ccx.external_srcs.insert(item.id, parent_id);
let mut my_id = 0;
match item.node {
ast::item_enum(_, _) => {
csearch::found(ast::ii_method(impl_did, is_provided, mth)) => {
ccx.stats.n_inlines += 1;
ccx.external.insert(fn_id, Some(mth.id));
+ ccx.external_srcs.insert(mth.id, fn_id);
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so don't.
if is_provided { return local_def(mth.id); }
use lib::llvm::ValueRef;
use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint};
use middle::trans::base::{trans_enum_variant,push_ctxt};
-use middle::trans::base::{trans_fn, decl_internal_cdecl_fn};
+use middle::trans::base::{trans_fn, decl_internal_rust_fn};
use middle::trans::base::{get_item_val, no_self};
use middle::trans::base;
use middle::trans::common::*;
use middle::trans::datum;
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;
ty::subst_tps(ccx.tcx, substs, None, llitem_ty)
}
};
- let llfty = type_of_fn_from_ty(ccx, mono_ty);
+
+ let f = match ty::get(mono_ty).sty {
+ ty::ty_bare_fn(ref f) => {
+ assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+ f
+ }
+ _ => fail!("expected bare rust fn or an intrinsic")
+ };
ccx.stats.n_monos += 1;
debug!("monomorphize_fn mangled to %s", s);
let mk_lldecl = || {
- let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
+ let lldecl = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
ccx.monomorphized.insert(hash_id, lldecl);
lldecl
};
sub_path,
"get_disr");
- let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
- let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
+ let llfdecl = decl_internal_rust_fn(ccx, [opaqueptrty], ty::mk_int(), sym);
let fcx = new_fn_ctxt(ccx,
~[],
llfdecl,
// Implementation detail. Shouldn't be public
#[allow(missing_doc)]
pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut Box<Vec<()>>, n: uint) {
-
+ // check for `uint` overflow
unsafe {
- let size_in_bytes = n * (*ty).size;
- if size_in_bytes > (**ptr).data.alloc {
- let total_size = size_in_bytes + sys::size_of::<Vec<()>>();
+ if n > (**ptr).data.alloc / (*ty).size {
+ let alloc = n * (*ty).size;
+ let total_size = alloc + sys::size_of::<Vec<()>>();
+ if alloc / (*ty).size != n || total_size < alloc {
+ fail!("vector size is too large: %u", n);
+ }
(*ptr) = local_realloc(*ptr as *(), total_size) as *mut Box<Vec<()>>;
- (**ptr).data.alloc = size_in_bytes;
+ (**ptr).data.alloc = alloc;
}
}
let mut tmp: uint = n - 1u;
let mut shift: uint = 1u;
while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
- return tmp + 1u;
+ tmp + 1u
+}
+
+/// Returns the smallest power of 2 greater than or equal to `n`
+#[inline]
+pub fn next_power_of_two_opt(n: uint) -> Option<uint> {
+ let halfbits: uint = sys::size_of::<uint>() * 4u;
+ let mut tmp: uint = n - 1u;
+ let mut shift: uint = 1u;
+ while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
+ tmp.checked_add(&1)
}
#[cfg(target_word_size = "32")]
let start_len = buf.len();
let mut total_read = 0;
- buf.reserve_at_least(start_len + len);
+ buf.reserve_additional(len);
vec::raw::set_len(buf, start_len + len);
do (|| {
use char::Char;
use clone::{Clone, DeepClone};
use container::{Container, Mutable};
-use num::Times;
-use iter::{Iterator, FromIterator, Extendable};
+use iter::{Iterator, FromIterator, Extendable, range};
use iter::{Filter, AdditiveIterator, Map};
use iter::{Invert, DoubleEndedIterator, ExactSize};
use libc;
use ptr::RawPtr;
use to_str::ToStr;
use uint;
-use unstable::raw::{Repr, Slice};
use vec;
use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
use default::Default;
fn concat(&self) -> ~str {
if self.is_empty() { return ~""; }
+ // `len` calculation may overflow but push_str but will check boundaries
let len = self.iter().map(|s| s.as_slice().len()).sum();
- let mut s = with_capacity(len);
+ let mut result = with_capacity(len);
- unsafe {
- do s.as_mut_buf |buf, _| {
- let mut buf = buf;
- for ss in self.iter() {
- do ss.as_slice().as_imm_buf |ssbuf, sslen| {
- ptr::copy_memory(buf, ssbuf, sslen);
- buf = buf.offset(sslen as int);
- }
- }
- }
- raw::set_len(&mut s, len);
+ for s in self.iter() {
+ result.push_str(s.as_slice())
}
- s
+ result
}
/// Concatenate a vector of strings, placing a given separator between each.
if sep.is_empty() { return self.concat(); }
// this is wrong without the guarantee that `self` is non-empty
+ // `len` calculation may overflow but push_str but will check boundaries
let len = sep.len() * (self.len() - 1)
+ self.iter().map(|s| s.as_slice().len()).sum();
- let mut s = ~"";
+ let mut result = with_capacity(len);
let mut first = true;
- s.reserve(len);
-
- unsafe {
- do s.as_mut_buf |buf, _| {
- do sep.as_imm_buf |sepbuf, seplen| {
- let mut buf = buf;
- for ss in self.iter() {
- do ss.as_slice().as_imm_buf |ssbuf, sslen| {
- if first {
- first = false;
- } else {
- ptr::copy_memory(buf, sepbuf, seplen);
- buf = buf.offset(seplen as int);
- }
- ptr::copy_memory(buf, ssbuf, sslen);
- buf = buf.offset(sslen as int);
- }
- }
- }
+ for s in self.iter() {
+ if first {
+ first = false;
+ } else {
+ result.push_str(sep);
}
- raw::set_len(&mut s, len);
+ result.push_str(s.as_slice());
}
- s
+ result
}
}
/// Unsafe operations
pub mod raw {
- use option::Some;
use cast;
use libc;
use ptr;
}
}
- /// Appends a byte to a string. (Not UTF-8 safe).
+ /// Appends a byte to a string.
+ /// The caller must preserve the valid UTF-8 property.
#[inline]
pub unsafe fn push_byte(s: &mut ~str, b: u8) {
- let v: &mut ~[u8] = cast::transmute(s);
- v.push(b);
+ as_owned_vec(s).push(b)
}
- /// Appends a vector of bytes to a string. (Not UTF-8 safe).
- unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
- let new_len = s.len() + bytes.len();
- s.reserve_at_least(new_len);
- for byte in bytes.iter() { push_byte(&mut *s, *byte); }
+ /// Appends a vector of bytes to a string.
+ /// The caller must preserve the valid UTF-8 property.
+ #[inline]
+ pub unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
+ vec::bytes::push_bytes(as_owned_vec(s), bytes);
}
- /// Removes the last byte from a string and returns it. (Not UTF-8 safe).
+ /// Removes the last byte from a string and returns it.
+ /// The caller must preserve the valid UTF-8 property.
pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
let len = s.len();
assert!((len > 0u));
return b;
}
- /// Removes the first byte from a string and returns it. (Not UTF-8 safe).
+ /// Removes the first byte from a string and returns it.
+ /// The caller must preserve the valid UTF-8 property.
pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
let len = s.len();
assert!((len > 0u));
return b;
}
+ /// Access the str in its vector representation.
+ /// The caller must preserve the valid UTF-8 property when modifying.
+ #[inline]
+ pub unsafe fn as_owned_vec<'a>(s: &'a mut ~str) -> &'a mut ~[u8] {
+ cast::transmute(s)
+ }
+
/// Sets the length of a string
///
/// This will explicitly set the size of the string, without actually
/// the string is actually the specified size.
#[inline]
pub unsafe fn set_len(s: &mut ~str, new_len: uint) {
- let v: &mut ~[u8] = cast::transmute(s);
- vec::raw::set_len(v, new_len)
+ vec::raw::set_len(as_owned_vec(s), new_len)
}
/// Sets the length of a string
/// Given a string, make a new string with repeated copies of it.
fn repeat(&self, nn: uint) -> ~str {
- do self.as_imm_buf |buf, len| {
- let mut ret = with_capacity(nn * len);
-
- unsafe {
- do ret.as_mut_buf |rbuf, _len| {
- let mut rbuf = rbuf;
-
- do nn.times {
- ptr::copy_memory(rbuf, buf, len);
- rbuf = rbuf.offset(len as int);
- }
- }
- raw::set_len(&mut ret, nn * len);
- }
- ret
+ let mut ret = with_capacity(nn * self.len());
+ for _ in range(0, nn) {
+ ret.push_str(*self);
}
+ ret
}
/// Retrieves the first character from a string slice and returns
/// Appends a string slice to the back of a string, without overallocating
#[inline]
fn push_str_no_overallocate(&mut self, rhs: &str) {
- unsafe {
- let llen = self.len();
- let rlen = rhs.len();
- self.reserve(llen + rlen);
- do self.as_imm_buf |lbuf, _llen| {
- do rhs.as_imm_buf |rbuf, _rlen| {
- let dst = ptr::offset(lbuf, llen as int);
- let dst = cast::transmute_mut_unsafe(dst);
- ptr::copy_memory(dst, rbuf, rlen);
- }
- }
- raw::set_len(self, llen + rlen);
- }
+ let new_cap = self.len() + rhs.len();
+ self.reserve(new_cap);
+ self.push_str(rhs);
}
/// Appends a string slice to the back of a string
#[inline]
fn push_str(&mut self, rhs: &str) {
unsafe {
- let llen = self.len();
- let rlen = rhs.len();
- self.reserve_at_least(llen + rlen);
- do self.as_imm_buf |lbuf, _llen| {
- do rhs.as_imm_buf |rbuf, _rlen| {
- let dst = ptr::offset(lbuf, llen as int);
- let dst = cast::transmute_mut_unsafe(dst);
- ptr::copy_memory(dst, rbuf, rlen);
- }
- }
- raw::set_len(self, llen + rlen);
+ raw::push_bytes(self, rhs.as_bytes());
}
}
#[inline]
fn push_char(&mut self, c: char) {
let cur_len = self.len();
- self.reserve_at_least(cur_len + 4); // may use up to 4 bytes
-
- // Attempt to not use an intermediate buffer by just pushing bytes
- // directly onto this string.
+ // may use up to 4 bytes.
unsafe {
- let v = self.repr();
- let len = c.encode_utf8(cast::transmute(Slice {
- data: ((&(*v).data) as *u8).offset(cur_len as int),
- len: 4,
- }));
- raw::set_len(self, cur_len + len);
+ raw::as_owned_vec(self).reserve_additional(4);
+
+ // Attempt to not use an intermediate buffer by just pushing bytes
+ // directly onto this string.
+ let used = do self.as_mut_buf |buf, _| {
+ do vec::raw::mut_buf_as_slice(buf.offset(cur_len as int), 4) |slc| {
+ c.encode_utf8(slc)
+ }
+ };
+ raw::set_len(self, cur_len + used);
}
}
#[inline]
fn reserve(&mut self, n: uint) {
unsafe {
- let v: &mut ~[u8] = cast::transmute(self);
- (*v).reserve(n);
+ raw::as_owned_vec(self).reserve(n)
}
}
/// * n - The number of bytes to reserve space for
#[inline]
fn reserve_at_least(&mut self, n: uint) {
- self.reserve(uint::next_power_of_two(n))
+ self.reserve(uint::next_power_of_two_opt(n).unwrap_or(n))
}
/// Returns the number of single-byte characters the string can hold without
#[inline]
fn as_mut_buf<T>(&mut self, f: &fn(*mut u8, uint) -> T) -> T {
- let v: &mut ~[u8] = unsafe { cast::transmute(self) };
- v.as_mut_buf(f)
+ unsafe {
+ raw::as_owned_vec(self).as_mut_buf(f)
+ }
}
}
with_capacity(100);
}
}
+
+ #[bench]
+ fn bench_push_str(bh: &mut BenchHarness) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+ do bh.iter {
+ let mut r = ~"";
+ r.push_str(s);
+ }
+ }
+
+ #[bench]
+ fn bench_connect(bh: &mut BenchHarness) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+ let sep = "→";
+ let v = [s, s, s, s, s, s, s, s, s, s];
+ do bh.iter {
+ assert_eq!(v.connect(sep).len(), s.len() * 10 + sep.len() * 9);
+ }
+ }
}
fn reserve(&mut self, n: uint);
fn reserve_at_least(&mut self, n: uint);
+ fn reserve_additional(&mut self, n: uint);
fn capacity(&self) -> uint;
fn shrink_to_fit(&mut self);
* # Arguments
*
* * n - The number of elements to reserve space for
+ *
+ * # Failure
+ *
+ * This method always succeeds in reserving space for `n` elements, or it does
+ * not return.
*/
fn reserve(&mut self, n: uint) {
// Only make the (slow) call into the runtime if we have to
*/
#[inline]
fn reserve_at_least(&mut self, n: uint) {
- self.reserve(uint::next_power_of_two(n));
+ self.reserve(uint::next_power_of_two_opt(n).unwrap_or(n));
+ }
+
+ /**
+ * Reserves capacity for at least `n` additional elements in the given vector.
+ *
+ * # Failure
+ *
+ * Fails if the new required capacity overflows uint.
+ *
+ * May also fail if `reserve` fails.
+ */
+ #[inline]
+ fn reserve_additional(&mut self, n: uint) {
+ if self.capacity() - self.len() < n {
+ match self.len().checked_add(&n) {
+ None => fail!("vec::reserve_additional: `uint` overflow"),
+ Some(new_cap) => self.reserve_at_least(new_cap)
+ }
+ }
}
/// Returns the number of elements the vector can hold without reallocating.
let repr: **Box<Vec<()>> = cast::transmute(&mut *self);
let fill = (**repr).data.fill;
if (**repr).data.alloc <= fill {
- let new_len = self.len() + 1;
- self.reserve_at_least(new_len);
+ self.reserve_additional(1);
}
push_fast(self, t);
let repr: **Vec<()> = cast::transmute(&mut *self);
let fill = (**repr).fill;
if (**repr).alloc <= fill {
- let new_len = self.len() + 1;
- self.reserve_at_least(new_len);
+ self.reserve_additional(1);
}
push_fast(self, t);
let self_len = self.len();
let rhs_len = rhs.len();
let new_len = self_len + rhs_len;
- self.reserve_at_least(new_len);
+ self.reserve_additional(rhs.len());
unsafe { // Note: infallible.
let self_p = vec::raw::to_mut_ptr(*self);
let rhs_p = vec::raw::to_ptr(rhs);
// Bound checks are done at vec::raw::copy_memory.
unsafe { vec::raw::copy_memory(dst, src, count) }
}
+
+ /**
+ * Allocate space in `dst` and append the data in `src`.
+ */
+ #[inline]
+ pub fn push_bytes(dst: &mut ~[u8], src: &[u8]) {
+ let old_len = dst.len();
+ dst.reserve_additional(src.len());
+ unsafe {
+ do dst.as_mut_buf |p_dst, len_dst| {
+ do src.as_imm_buf |p_src, len_src| {
+ ptr::copy_memory(p_dst.offset(len_dst as int), p_src, len_src)
+ }
+ }
+ vec::raw::set_len(dst, old_len + src.len());
+ }
+ }
}
impl<A: Clone> Clone for ~[A] {
v.push(2);
}
+ #[test]
+ #[should_fail]
+ fn test_overflow_does_not_cause_segfault_managed() {
+ let mut v = ~[@1];
+ v.reserve(-1);
+ v.push(@2);
+ }
+
#[test]
fn test_mut_split() {
let mut values = [1u8,2,3,4,5];
#[test] fn string_to_tts_1 () {
let (tts,_ps) = string_to_tts_and_sess(@"fn a (b : int) { b; }");
assert_eq!(to_json_str(@tts),
- ~"[\
- [\"tt_tok\",null,[\"IDENT\",\"fn\",false]],\
- [\"tt_tok\",null,[\"IDENT\",\"a\",false]],\
- [\
- \"tt_delim\",\
- [\
- [\"tt_tok\",null,\"LPAREN\"],\
- [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
- [\"tt_tok\",null,\"COLON\"],\
- [\"tt_tok\",null,[\"IDENT\",\"int\",false]],\
- [\"tt_tok\",null,\"RPAREN\"]\
+ ~"[\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"fn\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"a\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_delim\",\
+ \"fields\":[\
+ [\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"LPAREN\"\
]\
- ],\
- [\
- \"tt_delim\",\
- [\
- [\"tt_tok\",null,\"LBRACE\"],\
- [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
- [\"tt_tok\",null,\"SEMI\"],\
- [\"tt_tok\",null,\"RBRACE\"]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"b\",\
+ false\
+ ]\
+ }\
]\
- ]\
- ]"
- );
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"COLON\"\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"int\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"RPAREN\"\
+ ]\
+ }\
+ ]\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_delim\",\
+ \"fields\":[\
+ [\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"LBRACE\"\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"b\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"SEMI\"\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"RBRACE\"\
+ ]\
+ }\
+ ]\
+ ]\
+ }\
+]"
+ );
}
#[test] fn ret_expr() {
--- /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 = "numeric",
+ vers = "0.1")];
+#[crate_type = "lib"];
+
+pub trait Trig<T> {
+ fn sin(&self) -> T;
+}
+
+pub fn sin<T:Trig<R>, R>(theta: &T) -> R { theta.sin() }
+
+pub trait Angle<T>: Trig<T> {}
pub static global: int = 3;
+static global0: int = 4;
+pub static global2: &'static int = &global0;
+
pub fn verify_same(a: &'static int) {
let a = a as *int as uint;
let b = &global as *int as uint;
assert_eq!(a, b);
}
+pub fn verify_same2(a: &'static int) {
+ let a = a as *int as uint;
+ let b = global2 as *int as uint;
+ assert_eq!(a, b);
+}
+
condition!{ pub test: int -> (); }
pub fn raise() {
--- /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-4208-cc.rs
+// xfail-fast - Windows hates cross-crate tests
+
+extern mod numeric;
+use numeric::*;
+
+fn foo<T, A:Angle<T>>(theta: A) -> T { sin(&theta) }
+
+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.
+
+/*
+
+#5008 cast to &Trait causes code to segfault on method call
+
+It fixes itself if the &Trait is changed to @Trait.
+*/
+
+trait Debuggable {
+ fn debug_name(&self) -> ~str;
+}
+
+#[deriving(Clone)]
+struct Thing {
+name: ~str,
+}
+
+impl Thing {
+ fn new() -> Thing { Thing { name: ~"dummy" } }
+}
+
+impl Debuggable for Thing {
+ fn debug_name(&self) -> ~str { self.name.clone() }
+}
+
+fn print_name(x: &Debuggable)
+{
+ println(fmt!("debug_name = %s", x.debug_name()));
+}
+
+fn main() {
+ let thing = Thing::new();
+ print_name(&thing as &Debuggable);
+}
--- /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.
+
+/*
+#7519 ICE pattern matching unit in function argument
+*/
+
+fn foo(():()) { }
+
+fn main() {
+ 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.
+
+// xfail-pretty #9253 pretty printer doesn't preserve the bounds on trait objects
+
+/*
+
+#7673 Polymorphically creating traits barely works
+
+*/
+
+fn main() {}
+
+trait A {}
+impl<T: 'static> A for T {}
+
+fn owned1<T: 'static>(a: T) { ~a as ~A:; } /* note `:` */
+fn owned2<T: 'static>(a: ~T) { a as ~A:; }
+fn owned3<T: 'static>(a: ~T) { ~a as ~A:; }
+
+fn managed1<T: 'static>(a: T) { @a as @A; }
+fn managed2<T: 'static>(a: @T) { a as @A; }
+fn managed3<T: 'static>(a: @T) { @a as @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.
+
+/*
+
+#8171 Self is not recognised as implementing kinds in default method implementations
+
+*/
+
+fn require_send<T: Send>(_: T){}
+
+trait TragicallySelfIsNotSend: Send {
+ fn x(self) {
+ require_send(self);
+ }
+}
+
+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.
+
+/*
+
+#7770 ICE with sibling methods containing same-name-enum containing
+ same-name-member
+
+If you have two methods in an impl block, each containing an enum
+(with the same name), each containing at least one value with the same
+name, rustc gives the same LLVM symbol for the two of them and fails,
+as it does not include the method name in the symbol name.
+
+*/
+
+pub struct Foo;
+impl Foo {
+ pub fn foo() {
+ enum Panic { Common };
+ }
+ pub fn bar() {
+ enum Panic { Common };
+ }
+}
+
+/*
+#2074 duplicate symbols with enum in boxed closure
+*/
+
+fn foo() {
+ let one: @fn() -> uint = || {
+ enum r { a }
+ a as uint
+ };
+ let two: @fn() -> uint = || {
+ enum r { a }
+ a as uint
+ };
+ one(); two();
+}
+
+fn main() {}
pub fn main() {
other::verify_same(&other::global);
+ other::verify_same2(other::global2);
// Previously this fail'd because there were two addresses that were being
// used when declaring constants.