]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #9241 : alexcrichton/rust/build-rustdoc-ng, r=catamorphism
authorbors <bors@rust-lang.org>
Tue, 17 Sep 2013 13:00:45 +0000 (06:00 -0700)
committerbors <bors@rust-lang.org>
Tue, 17 Sep 2013 13:00:45 +0000 (06:00 -0700)
Now rustdoc_ng will be built as both a binary and a library (using the same
rules as all the other binaries that rust has). Furthermore, this will also
start building rustdoc_ng unit tests (and running them).

Note that some `rustdoc_ng` tests were removed, but @cmr says they weren't supposed to be there in the first place. The rustdoc_ng code should also be included in `make install` and `make dist` now.

35 files changed:
.gitattributes
doc/tutorial-rustpkg.md [new file with mode: 0644]
doc/tutorial.md
man/rustpkg.1
mk/platform.mk
src/libextra/json.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/build.rs
src/librustc/middle/trans/builder.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/closure.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/context.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/foreign.rs
src/librustc/middle/trans/inline.rs
src/librustc/middle/trans/monomorphize.rs
src/librustc/middle/trans/reflect.rs
src/libstd/at_vec.rs
src/libstd/num/uint.rs
src/libstd/rt/io/extensions.rs
src/libstd/str.rs
src/libstd/vec.rs
src/libsyntax/parse/mod.rs
src/test/auxiliary/issue-4208-cc.rs [new file with mode: 0644]
src/test/auxiliary/xcrate_static_addresses.rs
src/test/run-pass/issue-4208.rs [new file with mode: 0644]
src/test/run-pass/issue-5008-borrowed-traitobject-method-call.rs [new file with mode: 0644]
src/test/run-pass/issue-7519-match-unit-in-arg.rs [new file with mode: 0644]
src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs [new file with mode: 0644]
src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs [new file with mode: 0644]
src/test/run-pass/nested-enum-same-names.rs [new file with mode: 0644]
src/test/run-pass/xcrate-static-addresses.rs

index 10505d47e6c5d6d092d1b2fa619760df8055bc1a..70b2a5cd90ea032c72b119633e6d5f6b94aea76b 100644 (file)
@@ -1,6 +1,6 @@
 [attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
 
-* text=auto
+* text eol=lf
 *.cpp rust
 *.h rust
 *.rs rust
@@ -8,6 +8,3 @@ src/rt/msvc/* -whitespace
 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
diff --git a/doc/tutorial-rustpkg.md b/doc/tutorial-rustpkg.md
new file mode 100644 (file)
index 0000000..43d8309
--- /dev/null
@@ -0,0 +1,223 @@
+% 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.
index 637dbb10c23559616db7121f659a5cd804356e0d..7a9bb4adf65e352cb40533e7ffcae57a6b8fcbd5 100644 (file)
@@ -2979,6 +2979,7 @@ tutorials on individual topics.
 * [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.
 
@@ -2986,6 +2987,7 @@ There is further documentation on the [wiki], however those tend to be even more
 [tasks]: tutorial-tasks.html
 [macros]: tutorial-macros.html
 [ffi]: tutorial-ffi.html
+[rustpkg]: tutorial-rustpkg.html
 
 [wiki]: https://github.com/mozilla/rust/wiki/Docs
 
index a3178e616c6739536a141afd37552db037d5c2be..09564e86779e8acfa05d03152fd29203f8167b79 100644 (file)
@@ -11,6 +11,8 @@ This tool is a package manager for applications written in the Rust language,
 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
@@ -25,10 +27,6 @@ Remove all generated files from the \fIbuild\fR directory in the target's worksp
 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"
 
@@ -58,20 +56,9 @@ of the first entry in RUST_PATH.
 
 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
@@ -186,7 +173,7 @@ rust, rustc, rustdoc, rusti
 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"
index 6ee5420664d8e1c819efa0bfe8a000519b6a6a0d..ac6cf3c5451eb7292f5aa2f054de1e5ffee50097 100644 (file)
@@ -47,8 +47,11 @@ else
   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)
index f76dc05b2773d9e9b738f02e34dd06f5ae0c06f4..e0e860d102e056da13346c1d2e383fc0edfc8be4 100644 (file)
@@ -135,18 +135,21 @@ fn emit_enum_variant(&mut self,
                          _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("]}");
         }
     }
 
@@ -947,14 +950,20 @@ fn read_enum_variant<T>(&mut self,
         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),
         };
@@ -1517,7 +1526,7 @@ fn test_write_enum() {
                 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| {
@@ -1921,14 +1930,14 @@ fn test_decode_enum() {
         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);
 
index 692e4e345df63fb84ea128c48c226141b1fb5dca..9e65e4ec18a97685311070f4239efe2c9cd23e9a 100644 (file)
@@ -60,6 +60,7 @@ pub struct EncodeParams<'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: @mut cstore::CStore,
     encode_inlined_item: encode_inlined_item<'self>,
@@ -89,6 +90,7 @@ pub struct EncodeContext<'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>,
@@ -907,7 +909,9 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
         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, _) => {
@@ -1728,6 +1732,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         encode_inlined_item,
         link_meta,
         reachable,
+        non_inlineable_statics,
         _
     } = parms;
     let type_abbrevs = @mut HashMap::new();
@@ -1739,6 +1744,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         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,
index 62fbdc41b0e7046f34187a15e71b725ce7fd1d2d..d27bcde20649cf8fda14d52b1ebd5c928b0a526e 100644 (file)
@@ -324,15 +324,16 @@ fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result {
             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)));
index f0238e8f5c5501ee25fb5b9efba97ec386393c21..5b07e3210b0c8acba61b85dcc23c6f8a32b962a8 100644 (file)
@@ -174,6 +174,7 @@ fn drop(&self) {
     }
 }
 
+// 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 {
@@ -185,18 +186,12 @@ pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type)
     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) {
@@ -205,7 +200,73 @@ pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
     }
     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,
@@ -809,33 +870,30 @@ 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::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],
@@ -868,7 +926,8 @@ 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 {
@@ -1707,8 +1766,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
 // 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");
 
@@ -1726,23 +1784,7 @@ pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
     // 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) }
     }
 }
 
@@ -1896,8 +1938,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
 
     // 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") {
@@ -1961,18 +2002,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
            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,
@@ -2120,7 +2149,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
 
     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();
 
@@ -2298,10 +2327,28 @@ pub fn register_fn(ccx: @mut CrateContext,
                    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,
@@ -2494,12 +2541,29 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                     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);
@@ -2950,6 +3014,7 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_
             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,
index aabb389dde114b13d6fe22552a2e2e75d557c52f..4b03a2cac4b3ac09cc2a5c20ef246decbee915e9 100644 (file)
@@ -109,7 +109,8 @@ pub fn Invoke(cx: @mut Block,
               Fn: ValueRef,
               Args: &[ValueRef],
               Then: BasicBlockRef,
-              Catch: BasicBlockRef)
+              Catch: BasicBlockRef,
+              attributes: &[(uint, lib::llvm::Attribute)])
            -> ValueRef {
     if cx.unreachable {
         return C_null(Type::i8());
@@ -119,15 +120,7 @@ pub fn Invoke(cx: @mut Block,
     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) {
index 85e45942b7981d7cfe4e62ac36f2f4b594106151..d7a4dbb3510feb5e707f0369cca934fd0df0f061 100644 (file)
@@ -154,30 +154,25 @@ pub fn invoke(&self,
                   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 {
index 45da026afd06ac5d1df8bd7e9ec78102f6e5973d..54c905a4c1651352ab9b90eae0c399e0e3c84be5 100644 (file)
@@ -20,7 +20,7 @@
 
 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;
@@ -706,8 +706,26 @@ pub fn trans_call_inner(in_cx: @mut Block,
                 _ => {}
             }
 
+            // 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;
 
index 690d7343489e299909091845e09a8cf9cfb47c47..605032dc20c8fa0609361a1e7b3fa61976239795 100644 (file)
@@ -381,8 +381,10 @@ pub fn trans_expr_fn(bcx: @mut Block,
 
     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));
@@ -390,7 +392,7 @@ pub fn trans_expr_fn(bcx: @mut Block,
     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);
index 78d2228ff041c4d8550140c1335957d808df4a88..a7a04627981a97d0cf0955fa9bebb9c286f1de52 100644 (file)
@@ -84,21 +84,21 @@ pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: Type) -> ValueRef {
 }
 
 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));
     }
 }
 
@@ -157,7 +157,8 @@ fn const_deref(cx: &mut CrateContext, v: ValueRef, t: ty::t, explicit: bool)
     }
 }
 
-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) {
@@ -172,11 +173,14 @@ pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::DefId) -> ValueRef
             _ => 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 {
@@ -204,7 +208,10 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
                     // 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) |
@@ -250,17 +257,27 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
                          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);
 
@@ -269,7 +286,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
             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) }
@@ -338,13 +355,13 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                       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  => {
@@ -367,21 +384,21 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 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,
@@ -422,15 +439,15 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                   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;
@@ -476,17 +493,17 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 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);
@@ -500,24 +517,29 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
 
               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 {
@@ -528,7 +550,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 }
               }
               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)
@@ -537,7 +559,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 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")
             }
@@ -551,13 +573,13 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 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.
@@ -568,10 +590,10 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 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)) => {
@@ -583,12 +605,12 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                     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")
@@ -601,8 +623,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                   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);
@@ -610,13 +632,14 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                       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")
         };
index 6eb2fcf25fd3c289ff9113aa4c877ccd16099668..9ee7f09253b545f825511864e4c20d44d02be520 100644 (file)
@@ -61,6 +61,13 @@ pub struct CrateContext {
      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>,
@@ -189,6 +196,8 @@ pub fn new(sess: session::Session,
                   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(),
index b351fe91e6f1c859c644272ce71d66437b9e80d1..0a5578697583261f0fc5bb1fd75e235e36c6fa02 100644 (file)
 
 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;
@@ -987,6 +988,15 @@ fn trans_def_lvalue(bcx: @mut Block,
             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.
@@ -1018,7 +1028,6 @@ fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
                                                     llty.to_ref(),
                                                     buf)
                             };
-                            SetLinkage(llval, ExternalLinkage);
                             let extern_const_values = &mut bcx.ccx().extern_const_values;
                             extern_const_values.insert(did, llval);
                             llval
@@ -1026,6 +1035,7 @@ fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
                     }
                 }
 
+                let did = get_did(bcx.ccx(), did);
                 let val = get_val(bcx, did, const_ty);
                 DatumBlock {
                     bcx: bcx,
index 1ebe402bbb987838d3c41d9700c1db91680c36dc..b00d77d72ddb34650df328966483b8d4246e3e7b 100644 (file)
@@ -21,7 +21,6 @@
 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;
@@ -265,6 +264,9 @@ pub fn trans_native_call(bcx: @mut Block,
         }
     };
 
+    // 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)];
@@ -406,13 +408,12 @@ fn build_rust_fn(ccx: @mut CrateContext,
                 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, \
@@ -422,13 +423,12 @@ fn build_rust_fn(ccx: @mut CrateContext,
             }
         };
 
-        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,
@@ -500,7 +500,7 @@ unsafe fn build_wrap_fn(ccx: @mut CrateContext,
             // 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) => {
index cfc9c8a2e17cf3c1f2690f4e4642191c5b4e3b9d..a571e56a48ec06be63f121505e77cf8cb2b7079f 100644 (file)
@@ -8,7 +8,7 @@
 // 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};
@@ -53,16 +53,36 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
         }
         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(_, _) => {
@@ -86,6 +106,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
         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); }
index 2bdff6c8567fea52cf4e3c14fb7e7026b866fa69..ef055a52468c89be55e964653bf7fe9cb7289f99 100644 (file)
 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;
@@ -177,7 +176,14 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
             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;
 
@@ -200,7 +206,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
     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
     };
index 300fb64863ca8c0fad6b781b21d1562cc5e83855..23b87c63d6a2c5bb1ee02117eb586d42d484e5f3 100644 (file)
@@ -293,8 +293,7 @@ pub fn visit_ty(&mut self, t: ty::t) {
                                                                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,
index ce8e90e1a4324395f823a02201d7e223563b957c..42f511f722daba4323cd3cc6d9502b7294ea3974 100644 (file)
@@ -230,13 +230,16 @@ pub unsafe fn reserve<T>(v: &mut @[T], n: uint) {
     // 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;
             }
         }
 
index dfdd6cf72f742970d69e1c74607e8f123e89eebf..38a4df270fc23cabfa2b56e1fa18d9b26917ea97 100644 (file)
@@ -101,7 +101,17 @@ pub fn next_power_of_two(n: uint) -> uint {
     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")]
index e221f0ee94de72b10047cb1a686d59772358627b..1c48d6e7f1e1305ab569a57cb210554d2eb6d03b 100644 (file)
@@ -303,7 +303,7 @@ fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) {
             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 (|| {
index ccb39c605eb062bd3c4c9ea60fda544483a81dfc..bd484a5074c5ec38d057b4145d7a2d3fd0959beb 100644 (file)
@@ -22,8 +22,7 @@
 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;
@@ -33,7 +32,6 @@
 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;
@@ -185,23 +183,15 @@ impl<'self, S: Str> StrVector for &'self [S] {
     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.
@@ -212,34 +202,21 @@ fn connect(&self, sep: &str) -> ~str {
         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
     }
 }
 
@@ -961,7 +938,6 @@ macro_rules! utf8_acc_cont_byte(
 
 /// Unsafe operations
 pub mod raw {
-    use option::Some;
     use cast;
     use libc;
     use ptr;
@@ -1064,21 +1040,22 @@ pub unsafe fn slice_unchecked<'a>(s: &'a str, begin: uint, end: uint) -> &'a str
         }
     }
 
-    /// 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));
@@ -1087,7 +1064,8 @@ pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
         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));
@@ -1096,6 +1074,13 @@ pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
         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
@@ -1103,8 +1088,7 @@ pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
     /// 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
@@ -2061,22 +2045,11 @@ fn find_str(&self, needle: &str) -> Option<uint> {
 
     /// 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
@@ -2199,36 +2172,16 @@ impl OwnedStr for ~str {
     /// 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());
         }
     }
 
@@ -2236,17 +2189,18 @@ fn push_str(&mut self, rhs: &str) {
     #[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);
         }
     }
 
@@ -2306,8 +2260,7 @@ fn append(self, rhs: &str) -> ~str {
     #[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)
         }
     }
 
@@ -2329,7 +2282,7 @@ fn reserve(&mut self, n: uint) {
     /// * 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
@@ -2359,8 +2312,9 @@ fn into_bytes(self) -> ~[u8] {
 
     #[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)
+        }
     }
 }
 
@@ -3912,4 +3866,23 @@ fn bench_with_capacity(bh: &mut BenchHarness) {
             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);
+        }
+    }
 }
index 47c3a07961444b90a20af13de4b8cb0533fcaa27..9fc0eaf72b14d044de5d1fd8a0df90293de97d8e 100644 (file)
@@ -1245,6 +1245,7 @@ pub trait OwnedVector<T> {
 
     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);
 
@@ -1300,6 +1301,11 @@ fn move_rev_iter(self) -> MoveRevIterator<T> {
      * # 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
@@ -1340,7 +1346,26 @@ fn reserve(&mut self, n: uint) {
      */
     #[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.
@@ -1376,8 +1401,7 @@ fn push(&mut self, t: T) {
                 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);
@@ -1385,8 +1409,7 @@ fn push(&mut self, t: 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);
@@ -1432,7 +1455,7 @@ fn push_all_move(&mut self, mut rhs: ~[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);
@@ -2221,6 +2244,23 @@ pub fn copy_memory(dst: &mut [u8], src: &[u8], count: uint) {
         // 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] {
@@ -3619,6 +3659,14 @@ fn test_overflow_does_not_cause_segfault() {
         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];
index f7c76fee1809307380e6fb3cfa2115c215e52028..9645dab4e8b7b847c72c00b8296d03fa8cdaab73 100644 (file)
@@ -398,30 +398,130 @@ fn sp (a: uint, b: uint) -> Span {
     #[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() {
diff --git a/src/test/auxiliary/issue-4208-cc.rs b/src/test/auxiliary/issue-4208-cc.rs
new file mode 100644 (file)
index 0000000..26db69f
--- /dev/null
@@ -0,0 +1,21 @@
+// 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> {}
index 3a05462d856da20c25c56543abbaa85026b19e9d..f0df2b1e71edebff076623cce8d1208cb876325b 100644 (file)
 
 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() {
diff --git a/src/test/run-pass/issue-4208.rs b/src/test/run-pass/issue-4208.rs
new file mode 100644 (file)
index 0000000..e8b633c
--- /dev/null
@@ -0,0 +1,19 @@
+// 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() {}
diff --git a/src/test/run-pass/issue-5008-borrowed-traitobject-method-call.rs b/src/test/run-pass/issue-5008-borrowed-traitobject-method-call.rs
new file mode 100644 (file)
index 0000000..ce9bb72
--- /dev/null
@@ -0,0 +1,43 @@
+// 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);
+}
diff --git a/src/test/run-pass/issue-7519-match-unit-in-arg.rs b/src/test/run-pass/issue-7519-match-unit-in-arg.rs
new file mode 100644 (file)
index 0000000..ba84dd4
--- /dev/null
@@ -0,0 +1,19 @@
+// 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(());
+}
diff --git a/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs b/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs
new file mode 100644 (file)
index 0000000..1492b58
--- /dev/null
@@ -0,0 +1,30 @@
+// 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; }
diff --git a/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs b/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs
new file mode 100644 (file)
index 0000000..be68d50
--- /dev/null
@@ -0,0 +1,25 @@
+// 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(){}
diff --git a/src/test/run-pass/nested-enum-same-names.rs b/src/test/run-pass/nested-enum-same-names.rs
new file mode 100644 (file)
index 0000000..7d9b744
--- /dev/null
@@ -0,0 +1,49 @@
+// 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() {}
index 059a6f75ac82e2cbbdc92dc96bc64bb826dc0f36..7eb4adfd0675755a456d106406787d5a42389a52 100644 (file)
@@ -17,6 +17,7 @@
 
 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.