diff --git a/Makefile.in b/Makefile.in
index 676b4cfb7a015..a6b856622db5d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -38,7 +38,7 @@ CFG_STDLIB :=$(call CFG_LIB_NAME,std)
ifdef CFG_OCAMLC_OPT
$(info cfg: have ocaml native compiler)
OPT=.opt
-else
+else ifdef CFG_OCAMLC
$(info cfg: have only ocaml bytecode compiler)
endif
@@ -137,6 +137,12 @@ SREQ2 := stage2/rustc$(X) $(LREQ) stage3/glue.o stage3/$(CFG_STDLIB)
export CFG_SRC_DIR
+######################################################################
+# Subprograms
+######################################################################
+
+LLVM_AS := $(CFG_LLVM_BINDIR)/llvm-as
+
######################################################################
# Single-target rules
@@ -145,17 +151,21 @@ export CFG_SRC_DIR
all: rt/$(CFG_RUNTIME) \
rustllvm/$(CFG_RUSTLLVM) \
stage0/$(CFG_STDLIB) \
+ stage0/intrinsics.bc \
stage0/rustc$(X) \
$(GENERATED) \
$(DOCS) \
stage1/$(CFG_STDLIB) \
+ stage1/intrinsics.bc \
stage1/glue.o \
stage1/rustc$(X) \
stage2/$(CFG_STDLIB) \
+ stage2/intrinsics.bc \
stage2/glue.o \
stage2/rustc$(X) \
stage3/$(CFG_STDLIB) \
stage3/glue.o \
+ stage3/intrinsics.bc \
stage3/rustc$(X)
@@ -172,6 +182,7 @@ config.mk: $(S)configure $(S)Makefile.in
# Additional makefiles
######################################################################
+include $(CFG_SRC_DIR)/mk/intrinsics.mk
include $(CFG_SRC_DIR)/mk/stage0.mk
include $(CFG_SRC_DIR)/mk/stage1.mk
include $(CFG_SRC_DIR)/mk/stage2.mk
diff --git a/configure b/configure
index a2d6063a9a4b6..84833f12bcb6b 100755
--- a/configure
+++ b/configure
@@ -122,6 +122,7 @@ need_cmd find
need_cmd uname
need_cmd date
need_cmd tr
+need_cmd sed
msg "inspecting environment"
@@ -185,13 +186,13 @@ putvar CFG_CONFIGURE_ARGS
step_msg "looking for build programs"
probe_need CFG_GCC gcc
probe_need CFG_GIT git
-probe_need CFG_OCAMLC ocamlc
probe_need CFG_PERL perl
probe_need CFG_PYTHON python
probe_need CFG_CURL curl
probe CFG_LLVM_CONFIG llvm-config
probe CFG_VALGRIND valgrind
+probe CFG_OCAMLC ocamlc
probe CFG_OCAMLOPT ocamlopt
probe CFG_OCAMLC_OPT ocamlc.opt
probe CFG_OCAMLOPT_OPT ocamlopt.opt
@@ -215,6 +216,10 @@ then
--version \
| grep version \
| cut -d ' ' -f 5-)
+ CFG_LLVM_TRIPLE=$("$CFG_LLVM_BINDIR/llc" \
+ --version \
+ | grep Host: \
+ | cut -d ' ' -f 4-)
elif [ ! -z "$CFG_LLVM_CONFIG" ]
then
CFG_LLVM_VERSION=$(llvm-config --version)
@@ -224,6 +229,7 @@ then
CFG_LLVM_CXXFLAGS=$(llvm-config --cxxflags)
CFG_LLVM_LDFLAGS=$(llvm-config --ldflags)
CFG_LLVM_LIBS=$(llvm-config --libs)
+ CFG_LLVM_TRIPLE=$(llvm-config --host-target)
else
err "either the \"CFG_LLVM_ROOT\" environment variable must be set, or a \
\"llvm-config\" script must be present"
@@ -244,6 +250,7 @@ putvar CFG_LLVM_LIBDIR
putvar CFG_LLVM_CXXFLAGS
putvar CFG_LLVM_LDFLAGS
putvar CFG_LLVM_LIBS
+putvar CFG_LLVM_TRIPLE
# Munge any paths that appear in config.mk back to posix-y
perl -i.bak -p -e 's@ ([a-zA-Z]):[/\\]@ /\1/@go;' \
diff --git a/mk/intrinsics.mk b/mk/intrinsics.mk
new file mode 100644
index 0000000000000..77442ec530a49
--- /dev/null
+++ b/mk/intrinsics.mk
@@ -0,0 +1,19 @@
+######################################################################
+# intrinsics.bc rules
+######################################################################
+
+# TODO: Use clang to compile the C++.
+INTRINSICS_LL_IN := $(S)src/rt/intrinsics/intrinsics.ll.in
+INTRINSICS_LL := intrinsics/intrinsics.ll
+INTRINSICS_BC := intrinsics/intrinsics.bc
+
+$(INTRINSICS_LL): $(INTRINSICS_LL_IN) $(MKFILES)
+ @$(call E, mkdir: intrinsics)
+ $(Q)mkdir -p intrinsics
+ @$(call E, sed: $@)
+ $(Q)sed s/@CFG_LLVM_TRIPLE@/$(CFG_LLVM_TRIPLE)/g $< > $@
+
+$(INTRINSICS_BC): $(INTRINSICS_LL) $(MKFILES)
+ @$(call E, llvm-as: $@)
+ $(Q)$(LLVM_AS) -o $@ $<
+
diff --git a/mk/stage0.mk b/mk/stage0.mk
index 493f9e0058585..e79ae8435f95d 100644
--- a/mk/stage0.mk
+++ b/mk/stage0.mk
@@ -10,3 +10,9 @@ stage0/glue.o: stage0/rustc$(X)
stage0/$(CFG_STDLIB): stage0/rustc$(X)
$(Q)touch $@
+
+# TODO: Include as part of the snapshot.
+stage0/intrinsics.bc: $(INTRINSICS_BC)
+ @$(call E, cp: $@)
+ $(Q)cp $< $@
+
diff --git a/mk/stage1.mk b/mk/stage1.mk
index e01942a5695d7..eb30e78251156 100644
--- a/mk/stage1.mk
+++ b/mk/stage1.mk
@@ -1,5 +1,6 @@
stage1/std.o: $(STDLIB_CRATE) $(STDLIB_INPUTS) \
- stage0/rustc$(X) stage0/$(CFG_STDLIB) $(LREQ) $(MKFILES)
+ stage0/rustc$(X) stage0/$(CFG_STDLIB) stage0/intrinsics.bc \
+ $(LREQ) $(MKFILES)
@$(call E, compile: $@)
$(STAGE0) -c --shared -o $@ $<
@@ -12,10 +13,15 @@ stage1/rustc.o: $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ0)
@$(call E, compile: $@)
$(STAGE0) -c -o $@ $<
-stage1/glue.o: stage0/rustc$(X) stage0/$(CFG_STDLIB) $(LREQ) $(MKFILES)
+stage1/glue.o: stage0/rustc$(X) stage0/$(CFG_STDLIB) stage0/intrinsics.bc \
+ $(LREQ) $(MKFILES)
@$(call E, generate: $@)
$(STAGE0) -c -o $@ --glue
+stage1/intrinsics.bc: $(INTRINSICS_BC)
+ @$(call E, cp: $@)
+ $(Q)cp $< $@
+
# Due to make not wanting to run the same implicit rules twice on the same
# rule tree (implicit-rule recursion prevention, see "Chains of Implicit
# Rules" in GNU Make manual) we have to re-state the %.o and %.s patterns here
diff --git a/mk/stage2.mk b/mk/stage2.mk
index 600d55e4a74c5..74e76c3ce0380 100644
--- a/mk/stage2.mk
+++ b/mk/stage2.mk
@@ -1,4 +1,5 @@
-stage2/std.o: $(STDLIB_CRATE) $(STDLIB_INPUTS) stage1/rustc$(X) $(MKFILES)
+stage2/std.o: $(STDLIB_CRATE) $(STDLIB_INPUTS) stage1/rustc$(X) \
+ stage1/intrinsics.bc $(MKFILES)
@$(call E, compile: $@)
$(STAGE1) -c --shared -o $@ $<
@@ -11,11 +12,15 @@ stage2/rustc.o: $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ1)
@$(call E, compile: $@)
$(STAGE1) -c -o $@ $<
-stage2/glue.o: stage1/rustc$(X) stage1/$(CFG_STDLIB) \
- rustllvm/$(CFG_RUSTLLVM) rt/$(CFG_RUNTIME)
+stage2/glue.o: stage1/rustc$(X) stage1/$(CFG_STDLIB) stage1/intrinsics.bc \
+ rustllvm/$(CFG_RUSTLLVM) rt/$(CFG_RUNTIME)
@$(call E, generate: $@)
$(STAGE1) -c -o $@ --glue
+stage2/intrinsics.bc: $(INTRINSICS_BC)
+ @$(call E, cp: $@)
+ $(Q)cp $< $@
+
# Due to make not wanting to run the same implicit rules twice on the same
# rule tree (implicit-rule recursion prevention, see "Chains of Implicit
# Rules" in GNU Make manual) we have to re-state the %.o and %.s patterns here
diff --git a/mk/stage3.mk b/mk/stage3.mk
index 8f56637ef53c7..427f37f88ee4c 100644
--- a/mk/stage3.mk
+++ b/mk/stage3.mk
@@ -1,4 +1,5 @@
-stage3/std.o: $(STDLIB_CRATE) $(STDLIB_INPUTS) stage2/rustc$(X) $(MKFILES)
+stage3/std.o: $(STDLIB_CRATE) $(STDLIB_INPUTS) stage2/rustc$(X) \
+ stage2/intrinsics.bc $(MKFILES)
@$(call E, compile: $@)
$(STAGE2) -c --shared -o $@ $<
@@ -11,11 +12,15 @@ stage3/rustc.o: $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ2)
@$(call E, compile: $@)
$(STAGE2) -c -o $@ $<
-stage3/glue.o: stage2/rustc$(X) stage2/$(CFG_STDLIB) \
+stage3/glue.o: stage2/rustc$(X) stage2/$(CFG_STDLIB) stage2/intrinsics.bc \
rustllvm/$(CFG_RUSTLLVM) rt/$(CFG_RUNTIME)
@$(call E, generate: $@)
$(STAGE2) -c -o $@ --glue
+stage3/intrinsics.bc: $(INTRINSICS_BC)
+ @$(call E, cp: $@)
+ $(Q)cp $< $@
+
# Due to make not wanting to run the same implicit rules twice on the same
# rule tree (implicit-rule recursion prevention, see "Chains of Implicit
# Rules" in GNU Make manual) we have to re-state the %.o and %.s patterns here
diff --git a/mk/tests.mk b/mk/tests.mk
index 64185eeb52fe0..42eb05944df0d 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -139,10 +139,27 @@ ALL_TEST_SOURCES = $(TEST_CFAIL_SOURCES_STAGE0) \
unexport RUST_LOG
-check_nocompile: $(TEST_CFAIL_OUTS_STAGE0) \
+check-nocompile: $(TEST_CFAIL_OUTS_STAGE0) \
$(TEST_CFAIL_OUTS_STAGE1) \
$(TEST_CFAIL_OUTS_STAGE2)
+check-stage0: tidy \
+ $(TEST_RPASS_EXES_STAGE0) $(TEST_RFAIL_EXES_STAGE0) \
+ $(TEST_RPASS_OUTS_STAGE0) $(TEST_RFAIL_OUTS_STAGE0) \
+ $(TEST_CFAIL_OUTS_STAGE0) \
+
+
+check-stage1: tidy \
+ $(TEST_RPASS_EXES_STAGE1) $(TEST_RFAIL_EXES_STAGE1) \
+ $(TEST_RPASS_OUTS_STAGE1) $(TEST_RFAIL_OUTS_STAGE1) \
+ $(TEST_CFAIL_OUTS_STAGE1) \
+
+
+check-stage2: tidy \
+ $(TEST_RPASS_EXES_STAGE2) $(TEST_RFAIL_EXES_STAGE2) \
+ $(TEST_RPASS_OUTS_STAGE2) $(TEST_RFAIL_OUTS_STAGE2) \
+ $(TEST_CFAIL_OUTS_STAGE2) \
+
check: tidy \
$(TEST_RPASS_EXES_STAGE0) $(TEST_RFAIL_EXES_STAGE0) \
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index 6a37dece84515..4276b55806120 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -14,6 +14,7 @@ import middle.typestate_check;
import lib.llvm;
import util.common;
+import std.fs;
import std.map.mk_hashmap;
import std.option;
import std.option.some;
@@ -78,50 +79,39 @@ fn time[T](bool do_it, str what, fn()->T thunk) -> T {
}
fn compile_input(session.session sess,
- eval.env env,
- str input, str output,
- bool shared,
- bool optimize,
- bool debuginfo,
- bool verify,
- bool save_temps,
- trans.output_type ot,
- bool time_passes,
- bool run_typestate,
- vec[str] library_search_paths) {
+ eval.env env,
+ str input, str output) {
+ auto time_passes = sess.get_opts().time_passes;
auto def = tup(0, 0);
auto p = parser.new_parser(sess, env, def, input, 0u);
auto crate = time[@ast.crate](time_passes, "parsing",
- bind parse_input(sess, p, input));
- if (ot == trans.output_type_none) {ret;}
+ bind parse_input(sess, p, input));
+ if (sess.get_opts().output_type == trans.output_type_none) {ret;}
crate = time[@ast.crate](time_passes, "external crate reading",
- bind creader.read_crates(sess, crate, library_search_paths));
+ bind creader.read_crates(sess, crate));
crate = time[@ast.crate](time_passes, "resolution",
- bind resolve.resolve_crate(sess, crate));
+ bind resolve.resolve_crate(sess, crate));
time[()](time_passes, "capture checking",
- bind capture.check_for_captures(sess, crate));
+ bind capture.check_for_captures(sess, crate));
auto ty_cx = ty.mk_ctxt(sess);
auto typeck_result =
time[typeck.typecheck_result](time_passes, "typechecking",
- bind typeck.check_crate(ty_cx, crate));
+ bind typeck.check_crate(ty_cx, crate));
crate = typeck_result._0;
auto type_cache = typeck_result._1;
- if (run_typestate) {
+ if (sess.get_opts().run_typestate) {
crate = time[@ast.crate](time_passes, "typestate checking",
bind typestate_check.check_crate(crate));
}
auto llmod = time[llvm.ModuleRef](time_passes, "translation",
- bind trans.trans_crate(sess, crate, ty_cx, type_cache, output,
- debuginfo, shared));
+ bind trans.trans_crate(sess, crate, ty_cx, type_cache, output));
time[()](time_passes, "LLVM passes",
- bind trans.run_passes(llmod, optimize, debuginfo,
- verify, save_temps, output,
- ot));
+ bind trans.run_passes(sess, llmod, output));
}
fn pretty_print_input(session.session sess,
@@ -133,7 +123,7 @@ fn pretty_print_input(session.session sess,
pretty.pprust.print_file(crate.node.module, input, std.io.stdout());
}
-fn usage(session.session sess, str argv0) {
+fn usage(str argv0) {
io.stdout().write_str(#fmt("usage: %s [options] \n", argv0) + "
options:
@@ -152,6 +142,7 @@ options:
-c compile and assemble, but do not link
--save-temps write intermediate files in addition to normal output
--time-passes time the individual phases of the compiler
+ --sysroot override the system root (default: rustc's directory)
--no-typestate don't run the typestate pass (unsafe!)
-h display this message\n\n");
}
@@ -163,35 +154,40 @@ fn get_os() -> session.os {
if (_str.eq(s, "linux")) { ret session.os_linux; }
}
+fn get_default_sysroot(str binary) -> str {
+ auto dirname = fs.dirname(binary);
+ if (_str.eq(dirname, binary)) { ret "."; }
+ ret dirname;
+}
+
fn main(vec[str] args) {
// FIXME: don't hard-wire this.
- auto target_cfg = rec(os = get_os(),
- arch = session.arch_x86,
- int_type = common.ty_i32,
- uint_type = common.ty_u32,
- float_type = common.ty_f64 );
-
- auto crate_cache = common.new_int_hash[session.crate_metadata]();
- auto target_crate_num = 0;
- let vec[@ast.meta_item] md = vec();
- auto sess = session.session(target_crate_num, target_cfg, crate_cache,
- md, front.codemap.new_codemap());
+ let @session.config target_cfg =
+ @rec(os = get_os(),
+ arch = session.arch_x86,
+ int_type = common.ty_i32,
+ uint_type = common.ty_u32,
+ float_type = common.ty_f64);
auto opts = vec(optflag("h"), optflag("glue"),
optflag("pretty"), optflag("ls"), optflag("parse-only"),
optflag("O"), optflag("shared"), optmulti("L"),
optflag("S"), optflag("c"), optopt("o"), optopt("g"),
- optflag("save-temps"), optflag("time-passes"),
- optflag("no-typestate"), optflag("noverify"));
+ optflag("save-temps"), optopt("sysroot"),
+ optflag("time-passes"), optflag("no-typestate"),
+ optflag("noverify"));
auto binary = _vec.shift[str](args);
auto match;
alt (GetOpts.getopts(args, opts)) {
- case (GetOpts.failure(?f)) { sess.err(GetOpts.fail_str(f)); fail; }
+ case (GetOpts.failure(?f)) {
+ log_err #fmt("error: %s", GetOpts.fail_str(f));
+ fail;
+ }
case (GetOpts.success(?m)) { match = m; }
}
if (opt_present(match, "h")) {
- usage(sess, binary);
+ usage(binary);
ret;
}
@@ -201,13 +197,13 @@ fn main(vec[str] args) {
auto shared = opt_present(match, "shared");
auto output_file = GetOpts.opt_maybe_str(match, "o");
auto library_search_paths = GetOpts.opt_strs(match, "L");
- auto ot = trans.output_type_bitcode;
+ auto output_type = trans.output_type_bitcode;
if (opt_present(match, "parse-only")) {
- ot = trans.output_type_none;
+ output_type = trans.output_type_none;
} else if (opt_present(match, "S")) {
- ot = trans.output_type_assembly;
+ output_type = trans.output_type_assembly;
} else if (opt_present(match, "c")) {
- ot = trans.output_type_object;
+ output_type = trans.output_type_object;
}
auto verify = !opt_present(match, "noverify");
auto save_temps = opt_present(match, "save-temps");
@@ -216,6 +212,33 @@ fn main(vec[str] args) {
auto debuginfo = opt_present(match, "g");
auto time_passes = opt_present(match, "time-passes");
auto run_typestate = !opt_present(match, "no-typestate");
+ auto sysroot_opt = GetOpts.opt_maybe_str(match, "sysroot");
+
+ auto sysroot;
+ alt (sysroot_opt) {
+ case (none[str]) { sysroot = get_default_sysroot(binary); }
+ case (some[str](?s)) { sysroot = s; }
+ }
+
+ let @session.options sopts =
+ @rec(shared = shared,
+ optimize = optimize,
+ debuginfo = debuginfo,
+ verify = verify,
+ run_typestate = run_typestate,
+ save_temps = save_temps,
+ time_passes = time_passes,
+ output_type = output_type,
+ library_search_paths = library_search_paths,
+ sysroot = sysroot);
+
+ auto crate_cache = common.new_int_hash[session.crate_metadata]();
+ auto target_crate_num = 0;
+ let vec[@ast.meta_item] md = vec();
+ auto sess =
+ session.session(target_crate_num, target_cfg, sopts,
+ crate_cache, md, front.codemap.new_codemap());
+
auto n_inputs = _vec.len[str](match.free);
if (glue) {
@@ -223,7 +246,7 @@ fn main(vec[str] args) {
sess.err("No input files allowed with --glue.");
}
auto out = option.from_maybe[str]("glue.bc", output_file);
- middle.trans.make_common_glue(out, optimize, verify, save_temps, ot);
+ middle.trans.make_common_glue(sess, out);
ret;
}
@@ -244,18 +267,21 @@ fn main(vec[str] args) {
case (none[str]) {
let vec[str] parts = _str.split(ifile, '.' as u8);
_vec.pop[str](parts);
- parts += vec("bc");
+ alt (output_type) {
+ case (trans.output_type_none)
+ { parts += vec("pp"); }
+ case (trans.output_type_bitcode)
+ { parts += vec("bc"); }
+ case (trans.output_type_assembly)
+ { parts += vec("s"); }
+ case (trans.output_type_object)
+ { parts += vec("o"); }
+ }
auto ofile = _str.connect(parts, ".");
- compile_input(sess, env, ifile, ofile, shared,
- optimize, debuginfo, verify,
- save_temps, ot, time_passes,
- run_typestate, library_search_paths);
+ compile_input(sess, env, ifile, ofile);
}
case (some[str](?ofile)) {
- compile_input(sess, env, ifile, ofile, shared,
- optimize, debuginfo, verify,
- save_temps, ot, time_passes,
- run_typestate, library_search_paths);
+ compile_input(sess, env, ifile, ofile);
}
}
}
diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs
index 501b50b1ad6f7..6b3b55f44901d 100644
--- a/src/comp/driver/session.rs
+++ b/src/comp/driver/session.rs
@@ -19,11 +19,22 @@ tag arch {
arch_arm;
}
-type cfg = rec(os os,
- arch arch,
- ty_mach int_type,
- ty_mach uint_type,
- ty_mach float_type);
+type config = rec(os os,
+ arch arch,
+ ty_mach int_type,
+ ty_mach uint_type,
+ ty_mach float_type);
+
+type options = rec(bool shared,
+ bool optimize,
+ bool debuginfo,
+ bool verify,
+ bool run_typestate,
+ bool save_temps,
+ bool time_passes,
+ middle.trans.output_type output_type,
+ vec[str] library_search_paths,
+ str sysroot);
type crate_metadata = rec(str name,
vec[u8] data);
@@ -47,13 +58,18 @@ fn emit_diagnostic(span sp, str msg, str kind, u8 color, codemap.codemap cm) {
io.stdout().write_str(#fmt(" %s\n", msg));
}
-state obj session(ast.crate_num cnum, cfg targ,
+state obj session(ast.crate_num cnum,
+ @config targ_cfg, @options opts,
map.hashmap[int, crate_metadata] crates,
mutable vec[@ast.meta_item] metadata,
codemap.codemap cm) {
- fn get_targ_cfg() -> cfg {
- ret targ;
+ fn get_targ_cfg() -> @config {
+ ret targ_cfg;
+ }
+
+ fn get_opts() -> @options {
+ ret opts;
}
fn get_targ_crate_num() -> ast.crate_num {
diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs
index c8b31159444f7..cdbafe5a09990 100644
--- a/src/comp/front/creader.rs
+++ b/src/comp/front/creader.rs
@@ -459,12 +459,11 @@ fn fold_view_item_use(&env e, &span sp, ast.ident ident,
// Reads external crates referenced by "use" directives.
fn read_crates(session.session sess,
- @ast.crate crate,
- vec[str] library_search_paths) -> @ast.crate {
+ @ast.crate crate) -> @ast.crate {
auto e = @rec(
sess=sess,
crate_cache=@common.new_str_hash[int](),
- library_search_paths=library_search_paths,
+ library_search_paths=sess.get_opts().library_search_paths,
mutable next_crate_num=1
);
diff --git a/src/comp/front/extenv.rs b/src/comp/front/extenv.rs
new file mode 100644
index 0000000000000..6dc9c5ec021f5
--- /dev/null
+++ b/src/comp/front/extenv.rs
@@ -0,0 +1,68 @@
+/*
+ * The compiler code necessary to support the #env extension. Eventually this
+ * should all get sucked into either the compiler syntax extension plugin
+ * interface.
+ */
+
+import util.common;
+
+import std._str;
+import std._vec;
+import std.option;
+import std.GenericOS;
+
+export expand_syntax_ext;
+
+// FIXME: Need to thread parser through here to handle errors correctly
+fn expand_syntax_ext(parser.parser p,
+ common.span sp,
+ vec[@ast.expr] args,
+ option.t[str] body) -> @ast.expr {
+
+ if (_vec.len[@ast.expr](args) != 1u) {
+ p.err("malformed #env call");
+ }
+
+ auto var = expr_to_str(p, args.(0));
+ auto val = GenericOS.getenv(var);
+ ret make_new_str(sp, val);
+}
+
+// FIXME: duplicate code copied from extfmt.
+
+fn expr_to_str(parser.parser p,
+ @ast.expr expr) -> str {
+ alt (expr.node) {
+ case (ast.expr_lit(?l, _)) {
+ alt (l.node) {
+ case (ast.lit_str(?s)) {
+ ret s;
+ }
+ }
+ }
+ }
+ p.err("malformed #env call");
+ fail;
+}
+
+fn make_new_lit(common.span sp, ast.lit_ lit) -> @ast.expr {
+ auto sp_lit = @rec(node=lit, span=sp);
+ auto expr = ast.expr_lit(sp_lit, ast.ann_none);
+ ret @rec(node=expr, span=sp);
+}
+
+fn make_new_str(common.span sp, str s) -> @ast.expr {
+ auto lit = ast.lit_str(s);
+ ret make_new_lit(sp, lit);
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index e7a86d6efed1d..a7e355af5918e 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -948,6 +948,13 @@ fn expand_syntax_ext(parser p, ast.span sp,
expanded,
ast.ann_none);
+ ret newexpr;
+ } else if (_str.eq(extname, "env")) {
+ auto expanded = extenv.expand_syntax_ext(p, sp, args, body);
+ auto newexpr = ast.expr_ext(path, args, body,
+ expanded,
+ ast.ann_none);
+
ret newexpr;
} else {
p.err("unknown syntax extension");
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index 070174bad3c68..5e758bc66768b 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -848,7 +848,9 @@ native mod llvm = llvm_lib {
call. */
fn LLVMRustGetLastError() -> sbuf;
-
+ /** Links LLVM modules together. `Src` is destroyed by this call and
+ must never be referenced again. */
+ fn LLVMLinkModules(ModuleRef Dest, ModuleRef Src) -> Bool;
}
native mod rustllvm = llvm_lib {
diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs
index 2b4ad2a2f64cf..5f222cd43d9f6 100644
--- a/src/comp/middle/metadata.rs
+++ b/src/comp/middle/metadata.rs
@@ -687,9 +687,9 @@ fn encode_metadata(@trans.crate_ctxt cx, @ast.crate crate)
ret C_postr(string_w.get_str());
}
-fn write_metadata(@trans.crate_ctxt cx, bool shared, @ast.crate crate) {
+fn write_metadata(@trans.crate_ctxt cx, @ast.crate crate) {
auto llmeta = C_postr("");
- if (shared) {
+ if (cx.sess.get_opts().shared) {
llmeta = encode_metadata(cx, crate);
}
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 7e8e788efa8cc..3a654da8ae6ca 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -116,8 +116,7 @@ state type crate_ctxt = rec(session.session sess,
std.sha1.sha1 sha,
hashmap[ty.t, str] type_sha1s,
hashmap[ty.t, metadata.ty_abbrev] type_abbrevs,
- ty.ctxt tcx,
- bool debuginfo);
+ ty.ctxt tcx);
type local_ctxt = rec(vec[str] path,
vec[str] module_path,
@@ -1787,7 +1786,7 @@ fn declare_generic_glue(@local_ctxt cx,
TypeRef llfnty,
str name) -> ValueRef {
auto fn_nm;
- if (cx.ccx.debuginfo) {
+ if (cx.ccx.sess.get_opts().debuginfo) {
fn_nm = mangle_name_by_type_only(cx.ccx, t, "glue_" + name);
fn_nm = sanitize(fn_nm);
} else {
@@ -1972,9 +1971,7 @@ fn make_drop_glue(@block_ctxt cx, ValueRef v0, ty.t t) {
C_int(abi.obj_body_elt_tydesc)));
auto tydesc = cx.build.Load(tydescptr);
- // FIXME: disabled for now.
- // auto cx_ = maybe_call_dtor(cx, o);
- auto cx_ = cx;
+ auto cx_ = maybe_call_dtor(cx, o);
// Call through the obj's own fields-drop glue first.
call_tydesc_glue_full(cx_, body, tydesc,
@@ -2772,8 +2769,9 @@ fn maybe_call_dtor(@block_ctxt cx, ValueRef v) -> @block_ctxt {
vtbl = cx.build.Load(vtbl);
auto dtor_ptr = cx.build.GEP(vtbl, vec(C_int(0), C_int(0)));
dtor_ptr = cx.build.Load(dtor_ptr);
+ auto self_t = llvm.LLVMGetElementType(val_ty(v));
dtor_ptr = cx.build.BitCast(dtor_ptr,
- T_ptr(T_dtor(cx.fcx.lcx.ccx, val_ty(v))));
+ T_ptr(T_dtor(cx.fcx.lcx.ccx, self_t)));
auto dtor_cx = new_sub_block_ctxt(cx, "dtor");
auto after_cx = new_sub_block_ctxt(cx, "after_dtor");
@@ -2781,9 +2779,9 @@ fn maybe_call_dtor(@block_ctxt cx, ValueRef v) -> @block_ctxt {
C_null(val_ty(dtor_ptr)));
cx.build.CondBr(test, dtor_cx.llbb, after_cx.llbb);
- // FIXME need to pass type params (?)
+ auto me = dtor_cx.build.Load(v);
dtor_cx.build.FastCall(dtor_ptr, vec(C_null(T_ptr(T_nil())),
- cx.fcx.lltaskptr, v));
+ cx.fcx.lltaskptr, me));
dtor_cx.build.Br(after_cx.llbb);
ret after_cx;
}
@@ -6358,6 +6356,8 @@ fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid,
let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
+ // FIXME we should probably also allocate a box for empty objs that have a
+ // dtor, since otherwise they are never dropped, and the dtor never runs
if (_vec.len[ast.ty_param](ty_params) == 0u &&
_vec.len[ty.arg](arg_tys) == 0u) {
// Store null into pair, if no args or typarams.
@@ -7247,18 +7247,18 @@ fn is_object_or_assembly(output_type ot) -> bool {
ret false;
}
-fn run_passes(ModuleRef llmod, bool opt, bool dbg, bool verify,
- bool save_temps, str output, output_type ot) {
+fn run_passes(session.session sess, ModuleRef llmod, str output) {
auto pm = mk_pass_manager();
+ auto opts = sess.get_opts();
// TODO: run the linter here also, once there are llvm-c bindings for it.
// Generate a pre-optimization intermediate file if -save-temps was
// specified.
- if (save_temps) {
- alt (ot) {
+ if (opts.save_temps) {
+ alt (opts.output_type) {
case (output_type_bitcode) {
- if (opt) {
+ if (opts.optimize) {
auto filename = mk_intermediate_name(output, "no-opt.bc");
llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(filename));
}
@@ -7274,7 +7274,7 @@ fn run_passes(ModuleRef llmod, bool opt, bool dbg, bool verify,
// available in the C api.
// FIXME2: We might want to add optmization levels like -O1, -O2, -Os, etc
// FIXME3: Should we expose and use the pass lists used by the opt tool?
- if (opt) {
+ if (opts.optimize) {
auto fpm = mk_pass_manager();
// createStandardFunctionPasses
@@ -7330,25 +7330,25 @@ fn run_passes(ModuleRef llmod, bool opt, bool dbg, bool verify,
llvm.LLVMAddConstantMergePass(pm.llpm);
}
- if (verify) {
+ if (opts.verify) {
llvm.LLVMAddVerifierPass(pm.llpm);
}
// TODO: Write .s if -c was specified and -save-temps was on.
- if (is_object_or_assembly(ot)) {
+ if (is_object_or_assembly(opts.output_type)) {
let int LLVMAssemblyFile = 0;
let int LLVMObjectFile = 1;
let int LLVMNullFile = 2;
auto FileType;
- if (ot == output_type_object) {
+ if (opts.output_type == output_type_object) {
FileType = LLVMObjectFile;
} else {
FileType = LLVMAssemblyFile;
}
// Write optimized bitcode if --save-temps was on.
- if (save_temps) {
- alt (ot) {
+ if (opts.save_temps) {
+ alt (opts.output_type) {
case (output_type_bitcode) { /* nothing to do */ }
case (_) {
auto filename = mk_intermediate_name(output, "opt.bc");
@@ -7712,8 +7712,7 @@ fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
vec_append_glue = make_vec_append_glue(llmod, tn));
}
-fn make_common_glue(str output, bool optimize, bool verify, bool save_temps,
- output_type ot) {
+fn make_common_glue(session.session sess, str output) {
// FIXME: part of this is repetitive and is probably a good idea
// to autogen it, but things like the memcpy implementation are not
// and it might be better to just check in a .ll file.
@@ -7739,7 +7738,7 @@ fn make_common_glue(str output, bool optimize, bool verify, bool save_temps,
trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);
- run_passes(llmod, optimize, false, verify, save_temps, output, ot);
+ run_passes(sess, llmod, output);
}
fn create_module_map(@crate_ctxt ccx) -> ValueRef {
@@ -7791,8 +7790,7 @@ fn create_crate_map(@crate_ctxt ccx) -> ValueRef {
}
fn trans_crate(session.session sess, @ast.crate crate, ty.ctxt tcx,
- ty.type_cache type_cache, str output,
- bool debuginfo, bool shared)
+ ty.type_cache type_cache, str output)
-> ModuleRef {
auto llmod =
llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
@@ -7842,8 +7840,7 @@ fn trans_crate(session.session sess, @ast.crate crate, ty.ctxt tcx,
sha = std.sha1.mk_sha1(),
type_sha1s = sha1s,
type_abbrevs = abbrevs,
- tcx = tcx,
- debuginfo = debuginfo);
+ tcx = tcx);
auto cx = new_local_ctxt(ccx);
create_typedefs(ccx);
@@ -7854,12 +7851,12 @@ fn trans_crate(session.session sess, @ast.crate crate, ty.ctxt tcx,
trans_mod(cx, crate.node.module);
trans_vec_append_glue(cx);
auto crate_map = create_crate_map(ccx);
- if (!shared) {
+ if (!sess.get_opts().shared) {
trans_main_fn(cx, crate_ptr, crate_map);
}
// Translate the metadata.
- middle.metadata.write_metadata(cx.ccx, shared, crate);
+ middle.metadata.write_metadata(cx.ccx, crate);
ret llmod;
}
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index b506947a9c7c4..3074a84d07419 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -24,6 +24,7 @@ mod front {
mod ast;
mod creader;
mod extfmt;
+ mod extenv;
mod codemap;
mod lexer;
mod parser;
diff --git a/src/rt/intrinsics/intrinsics.ll.in b/src/rt/intrinsics/intrinsics.ll.in
index ebd5d15cff4a7..2a05555ef0261 100644
--- a/src/rt/intrinsics/intrinsics.ll.in
+++ b/src/rt/intrinsics/intrinsics.ll.in
@@ -1,6 +1,6 @@
; ModuleID = 'intrinsics.cpp'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
-target triple = "$(LLVM_TRIPLE)"
+target triple = "@CFG_LLVM_TRIPLE@"
%0 = type { i32, i8**, i32 }
%1 = type { %"struct.hash_map *>::map_entry"* }
diff --git a/src/rt/memcheck.h b/src/rt/memcheck.h
index bf95491b9b8cf..58480256e19dc 100644
--- a/src/rt/memcheck.h
+++ b/src/rt/memcheck.h
@@ -184,7 +184,7 @@ typedef
/* Do a full memory leak check (like --leak-check=full) mid-execution. */
#define VALGRIND_DO_LEAK_CHECK \
- {unsigned long _qzz_res; \
+ {unsigned long _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DO_LEAK_CHECK, \
0, 0, 0, 0, 0); \
@@ -192,7 +192,7 @@ typedef
/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
#define VALGRIND_DO_QUICK_LEAK_CHECK \
- {unsigned long _qzz_res; \
+ {unsigned long _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DO_LEAK_CHECK, \
1, 0, 0, 0, 0); \
@@ -207,7 +207,7 @@ typedef
are. We also initialise '_qzz_leaked', etc because
VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
defined. */ \
- {unsigned long _qzz_res; \
+ {unsigned long _qzz_res __attribute((unused)); \
unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \
unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
@@ -229,7 +229,7 @@ typedef
are. We also initialise '_qzz_leaked', etc because
VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
defined. */ \
- {unsigned long _qzz_res; \
+ {unsigned long _qzz_res __attribute((unused)); \
unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \
unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
diff --git a/src/rt/valgrind.h b/src/rt/valgrind.h
index 0bae0aa130eec..737cc2a8b4224 100644
--- a/src/rt/valgrind.h
+++ b/src/rt/valgrind.h
@@ -4403,7 +4403,7 @@ vg_VALGRIND_DO_CLIENT_REQUEST_EXPR(uintptr_t _zzq_default,
since it provides a way to make sure valgrind will retranslate the
invalidated area. Returns no value. */
#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DISCARD_TRANSLATIONS, \
_qzz_addr, _qzz_len, 0, 0, 0); \
@@ -4652,7 +4652,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
Ignored if addr == 0.
*/
#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MALLOCLIKE_BLOCK, \
addr, sizeB, rzB, is_zeroed, 0); \
@@ -4662,7 +4662,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
Ignored if addr == 0.
*/
#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__FREELIKE_BLOCK, \
addr, rzB, 0, 0, 0); \
@@ -4670,7 +4670,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Create a memory pool. */
#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__CREATE_MEMPOOL, \
pool, rzB, is_zeroed, 0, 0); \
@@ -4678,7 +4678,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Destroy a memory pool. */
#define VALGRIND_DESTROY_MEMPOOL(pool) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DESTROY_MEMPOOL, \
pool, 0, 0, 0, 0); \
@@ -4686,7 +4686,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Associate a piece of memory with a memory pool. */
#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_ALLOC, \
pool, addr, size, 0, 0); \
@@ -4694,7 +4694,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Disassociate a piece of memory from a memory pool. */
#define VALGRIND_MEMPOOL_FREE(pool, addr) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_FREE, \
pool, addr, 0, 0, 0); \
@@ -4702,7 +4702,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Disassociate any pieces outside a particular range. */
#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_TRIM, \
pool, addr, size, 0, 0); \
@@ -4710,7 +4710,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Resize and/or move a piece associated with a memory pool. */
#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MOVE_MEMPOOL, \
poolA, poolB, 0, 0, 0); \
@@ -4718,7 +4718,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Resize and/or move a piece associated with a memory pool. */
#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_CHANGE, \
pool, addrA, addrB, size, 0); \
@@ -4747,7 +4747,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Unmark the piece of memory associated with a stack id as being a
stack. */
#define VALGRIND_STACK_DEREGISTER(id) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__STACK_DEREGISTER, \
id, 0, 0, 0, 0); \
@@ -4755,7 +4755,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Change the start and end address of the stack id. */
#define VALGRIND_STACK_CHANGE(id, start, end) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__STACK_CHANGE, \
id, start, end, 0, 0); \
@@ -4763,7 +4763,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
/* Load PDB debug info for Wine PE image_map. */
#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__LOAD_PDB_DEBUGINFO, \
fd, ptr, total_size, delta, 0); \
@@ -4774,7 +4774,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
result will be dumped in there and is guaranteed to be zero
terminated. If no info is found, the first byte is set to zero. */
#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \
- {unsigned int _qzz_res; \
+ {unsigned int _qzz_res __attribute((unused)); \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MAP_IP_TO_SRCLOC, \
addr, buf64, 0, 0, 0); \
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 6d342b0cad70c..01ea6677be126 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Linker.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/FormattedStream.h"
@@ -25,12 +26,13 @@
using namespace llvm;
-static char *LLVMRustError;
+static const char *LLVMRustError;
extern "C" LLVMMemoryBufferRef
LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
LLVMMemoryBufferRef MemBuf = NULL;
- LLVMCreateMemoryBufferWithContentsOfFile(Path, &MemBuf, &LLVMRustError);
+ LLVMCreateMemoryBufferWithContentsOfFile(Path, &MemBuf,
+ const_cast(&LLVMRustError));
return MemBuf;
}
@@ -49,8 +51,24 @@ enum LLVMCodeGenFileType {
LLVMNullFile // Do not emit any output.
};
-extern "C" void LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, LLVMModuleRef M,
- const char *triple, const char *path,
+extern "C" bool LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src) {
+ static std::string err;
+
+ // For some strange reason, unwrap() doesn't work here. "No matching
+ // function" error.
+ Module *DM = reinterpret_cast(Dest);
+ Module *SM = reinterpret_cast(Src);
+ if (Linker::LinkModules(DM, SM, &err)) {
+ LLVMRustError = err.c_str();
+ return false;
+ }
+ return true;
+}
+
+extern "C" void LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
+ LLVMModuleRef M,
+ const char *triple,
+ const char *path,
LLVMCodeGenFileType FileType) {
// Set compilation options.
diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in
index 0bd524c21cb66..74acb28bb9ccd 100644
--- a/src/rustllvm/rustllvm.def.in
+++ b/src/rustllvm/rustllvm.def.in
@@ -1,6 +1,7 @@
LLVMRustCreateMemoryBufferWithContentsOfFile
LLVMRustWriteOutputFile
LLVMRustGetLastError
+LLVMLinkModules
LLVMCreateObjectFile
LLVMDisposeObjectFile
LLVMGetSections
diff --git a/src/snapshots.txt b/src/snapshots.txt
index caa021e47bd4f..9187f59e51828 100644
--- a/src/snapshots.txt
+++ b/src/snapshots.txt
@@ -1,3 +1,8 @@
+S 2011-05-04 add7d34
+ linux-i386 a85df9efb67bf83c5d71218a90d2a4935de2bec3
+ macos-i386 68e40fddb4aa9ac86a0fa93e7c36d461698e204e
+ winnt-i386 fbc7bf335af774cc7f904ceba725f18acbb5fcd9
+
S 2011-05-04 4642d7a
linux-i386 631d4c375a8cc74de77c2f9aa79d3c404f8c353b
macos-i386 61b5a0eebb4eea8242d5cbc4a9967882b6a99cb4