diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 0f05db86742eb..8dcaa4b5064c1 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -616,6 +616,7 @@ extern { C: ContextRef) -> ModuleRef; pub fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef; + pub fn LLVMCloneModule(M: ModuleRef) -> ModuleRef; pub fn LLVMDisposeModule(M: ModuleRef); /// Data layout. See Module::getDataLayout. diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 4815a399d9913..5b38004396bac 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -545,10 +545,22 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_asm { let path = output_names.with_extension(&format!("{}.s", name_extra)); + + // We can't use the same module for asm and binary output, because that triggers + // various errors like invalid IR or broken binaries, so we might have to clone the + // module to produce the asm output + let llmod = if config.emit_obj { + llvm::LLVMCloneModule(llmod) + } else { + llmod + }; with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::AssemblyFileType); }); + if config.emit_obj { + llvm::LLVMDisposeModule(llmod); + } } if config.emit_obj { diff --git a/src/test/run-make/emit/Makefile b/src/test/run-make/emit/Makefile new file mode 100644 index 0000000000000..be34028fe1d01 --- /dev/null +++ b/src/test/run-make/emit/Makefile @@ -0,0 +1,15 @@ +-include ../tools.mk + +all: + $(RUSTC) -Copt-level=0 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs + $(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs + $(RUSTC) -Copt-level=2 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs + $(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs + $(RUSTC) -Copt-level=0 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs + $(call RUN,test-26235) || exit 1 + $(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs + $(call RUN,test-26235) || exit 1 + $(RUSTC) -Copt-level=2 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs + $(call RUN,test-26235) || exit 1 + $(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs + $(call RUN,test-26235) || exit 1 diff --git a/src/test/run-make/emit/test-24876.rs b/src/test/run-make/emit/test-24876.rs new file mode 100644 index 0000000000000..ab69decbf007e --- /dev/null +++ b/src/test/run-make/emit/test-24876.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks for issue #24876 + +fn main() { + let mut v = 0; + for i in 0..0 { + v += i; + } + println!("{}", v) +} diff --git a/src/test/run-make/emit/test-26235.rs b/src/test/run-make/emit/test-26235.rs new file mode 100644 index 0000000000000..97b58a3671bf3 --- /dev/null +++ b/src/test/run-make/emit/test-26235.rs @@ -0,0 +1,56 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks for issue #26235 + +fn main() { + use std::thread; + + type Key = u32; + const NUM_THREADS: usize = 2; + + #[derive(Clone,Copy)] + struct Stats { + upsert: S, + delete: S, + insert: S, + update: S + }; + + impl Stats where S: Copy { + fn dot(self, s: Stats, f: F) -> Stats where F: Fn(S, T) -> B { + let Stats { upsert: u1, delete: d1, insert: i1, update: p1 } = self; + let Stats { upsert: u2, delete: d2, insert: i2, update: p2 } = s; + Stats { upsert: f(u1, u2), delete: f(d1, d2), insert: f(i1, i2), update: f(p1, p2) } + } + + fn new(init: S) -> Self { + Stats { upsert: init, delete: init, insert: init, update: init } + } + } + + fn make_threads() -> Vec> { + let mut t = Vec::with_capacity(NUM_THREADS); + for _ in 0..NUM_THREADS { + t.push(thread::spawn(move || {})); + } + t + } + + let stats = [Stats::new(0); NUM_THREADS]; + make_threads(); + + { + let Stats { ref upsert, ref delete, ref insert, ref update } = stats.iter().fold( + Stats::new(0), |res, &s| res.dot(s, |x: Key, y: Key| x.wrapping_add(y))); + println!("upserts: {}, deletes: {}, inserts: {}, updates: {}", + upsert, delete, insert, update); + } +}